I have some IDs that I want to eventually loop into a larger variable:
playerId <- c(12345, 23456, 34567)
But to first do that, I need to use sprintf to create the necessary lines of code that will run correctly in an API request that looks like something like this when I'm running one at a time:
POST(
'https://api.secure.com/v1/Test',
accept_json(),
content_type_json(),
add_headers(Authorization = VanAPI),
encode = "json",
body=list(playerId = 12345)
)
When I run the above request, it works just fine. But for the purposes of a loop, I want it to look like this:
POST(
'https://api.secure.com/v1/Test',
accept_json(),
content_type_json(),
add_headers(Authorization = ApiKey),
encode = "json",
PlayerIdLines
)
So what I'm doing is creating a series of the necessary line I need for each ID:
PlayerIdLines <- cat(sprintf('body=list(playerId = %s\n)', playerId))
When I first run that line, it produces this output:
> PlayerIdLines <- cat(sprintf('body=list(playerId = %s\n)', playerId))
body=list(targetId = 12345
) body=list(targetId = 23456
) body=list(targetId = 34567
)
But then after that, whenever I try to execute variable PlayerIdLines, all it does is return null:
> PlayerIdLines
NULL
Why is that happening? Why is it being stored as NULL?
EDIT: BASED ON MR FLICK'S ANSWER
I try running the following:
get_data <- function(url) {
POST(
'https://api.secure.com/v1/Test',
accept_json(),
content_type_json(),
add_headers(Authorization = VanAPI),
encode = "json",
body=list(playerId = playerId)
)
}
map_df(playerIds, get_data, .id = 'log') -> CreateDF
But I'm met with the following error:
Error: Argument 1 must be a data frame or a named atomic vector.
Related
Im trying to create an API that receives an ID, queries a MSSQL database and returns back a result.
#* #apiTitle IdCx
#* #apiDescription A test
#* #get /IdCx
#*
apiFn <- function(id) {
require(odbc)
require(glue)
dbcon <- dbConnect(odbc::odbc()
,dsn = "test"
,database = "testDB"
,uid = user1
,pwd = pass1
,Trusted_Connection= "No"
,encoding = "UTF-8"
)
IdCx = dbGetQuery(dbcon, glue_sql('SELECT max (CC.IdCx)
FROM table CC
where IdA in ({id})
'))
as.numeric(IdCx)
}
After creating the R file main.R, I execute it:
apiTest <- pr("main.R")
pr_run(apiTest)
But I get this error
{
"error": "500 - Internal server error",
"message": "Error in h(simpleError(msg, call)): error in evaluating the argument 'statement' in selecting a method for function 'dbGetQuery': error in evaluating the argument 'conn' in selecting a method for function 'dbQuoteLiteral': el argumento \".con\" is missing, with no default\n"
}
But if I deliberately insert a fixed id=1365350 inside the code (just for testing), the API will return a correct result
#* #apiTitle IdCx
#* #apiDescription A test
#* #get /IdCx
#*
apiFn<- function(id) {
require(odbc)
require(glue)
id=1365350
dbcon <- dbConnect(odbc::odbc()
,dsn = "venus"
,database = "DWHICV"
,uid = Sys.getenv("sql_reportes_id")
,pwd = Sys.getenv("sql_reportes_pw")
,Trusted_Connection= "No"
,encoding = "UTF-8"
)
IdCx = dbGetQuery(dbcon, glue_sql('SELECT max (CC.IdCx)
FROM hceCxCirugia CC
where IdAtencion in ({id})
'))
as.numeric(IdCx)
}
Including #* #param IdA wont fix the error
Figured it out. Eventhough I never used the parameter .con inside the glue_sql function when running it from RStudio, apparently is mandatory when using plumber API.
IdCx = dbGetQuery(dbcon, glue_sql('SELECT max (CC.IdCx)
FROM table CC
where IdA in ({id})
,.con = dbcon))
I am trying to programmatically update my Figshare repository using rapiclient.
Following the answer to this question, I managed to authenticate and see my repository by:
library(rapiclient)
library(httr)
# figshare repo id
id = 3761562
fs_api <- get_api("https://docs.figshare.com/swagger.json")
header <- c(Authorization = sprintf("token %s", Sys.getenv("RFIGSHARE_PAT")))
fs_api <- list(operations = get_operations(fs_api, header),
schemas = get_schemas(fs_api))
reply <- fs_api$operations$article_files(id)
I also managed to delete a file using:
fs_api$operations$private_article_file_delete(article_id = id, file_id = F)
Now, I would like to upload a new file to the repository. There seem to be two methods I need:
fs_api$operations$private_article_upload_initiate
fs_api$operations$private_article_upload_complete
But I do not understand the documentation. According to fs_api$operations$private_article_upload_initiate help:
> fs_api$operations$private_article_upload_initiate
private_article_upload_initiate
Initiate Upload
Description:
Initiate new file upload within the article. Either use link to
provide only an existing file that will not be uploaded on figshare
or use the other 3 parameters(md5, name, size)
Parameters:
link (string)
Url for an existing file that will not be uploaded on figshare
md5 (string)
MD5 sum pre computed on the client side
name (string)
File name including the extension; can be omitted only for linked
files.
size (integer)
File size in bytes; can be omitted only for linked files.
What does "file that will not be uploaded on Figshare" mean? How would I use the API to upload a local file ~/foo.txt?
fs_api$operations$private_article_upload_initiate(link='~/foo.txt')
returns HTTP 400.
I feel like I sent you down a bad path with my previous answer because I am not sure how to edit some of the api endpoints when using rapiclient. For example, the corresponding endpoint for fs_api$operations$private_article_upload_initiate() will be https://api.figshare.com/v2/account/articles/{article_id}/files, and I am not sure how to substitute for {article_id} prior to sending the request.
You may have to define your own client for operations you cannot get working any other way.
Here is an example of uploading a file to an existing private article as per the goal of your question.
library(httr)
# id of previously created figshare article
my_article_id <- 99999999
# make example file to upload
my_file <- tempfile("my_file", fileext = ".txt")
writeLines("Hello World!", my_file)
# Step 1 initiate upload
# https://docs.figshare.com/#private_article_upload_initiate
r <- POST(
url = sprintf("https://api.figshare.com/v2/account/articles/%s/files", my_article_id),
add_headers(c(Authorization = sprintf("token %s", Sys.getenv("RFIGSHARE_PAT")))),
body = list(
md5 = tools::md5sum(my_file)[[1]],
name = basename(my_file),
size = file.size(my_file)
),
encode = "json"
)
initiate_upload_response <- content(r)
# Step 2 single file info (get upload url)
# https://docs.figshare.com/#private_article_file
r <- GET(url = initiate_upload_response$location,
add_headers(c(Authorization = sprintf("token %s", Sys.getenv("RFIGSHARE_PAT"))))
)
single_file_response <- content(r)
# Step 3 uploader service (get number of upload parts required)
# https://docs.figshare.com/#endpoints
r <- GET(url = single_file_response$upload_url,
add_headers(c(Authorization = sprintf("token %s", Sys.getenv("RFIGSHARE_PAT"))))
)
upload_service_response <- content(r)
# Step 4 upload parts (this example only has one part)
# https://docs.figshare.com/#endpoints_1
r <- PUT(url = single_file_response$upload_url, path = 1,
add_headers(c(Authorization = sprintf("token %s", Sys.getenv("RFIGSHARE_PAT")))),
body = upload_file(my_file)
)
upload_parts_response <- content(r)
# Step 5 complete upload (after all part uploads are successful)
# https://docs.figshare.com/#private_article_upload_complete
r <- POST(
url = initiate_upload_response$location,
add_headers(c(Authorization = sprintf("token %s", Sys.getenv("RFIGSHARE_PAT"))))
)
complete_upload_response <- content(r)
Trying to move on from my troubles with RISmed (see Problems with RISmed and large(ish) data sets), I decided to use rentrez and entrez_summary to retrieve a large list of pubmed titles from a query:
set_entrez_key("######") #I did provide my real API key here
Sys.getenv("ENTREZ_KEY")
rm(list=ls())
library(rentrez)
query="(United States[AD] AND France[AD] AND 1995:2020[PDAT])"
results<-entrez_search(db="pubmed",term=query,use_history=TRUE)
results
results$web_history
for (seq_start in seq(0, results$count, 100)) {
if (seq_start == 0) {
summary.append.l <- entrez_summary(
db = "pubmed",
web_history = results$web_history,
retmax = 100,
retstart = seq_start
)
}
Sys.sleep(0.1) #slow things down in case THAT'S a factor here....
summary.append.l <- append(
summary.append.l,
entrez_summary(
db = "pubmed",
web_history = results$web_history,
retmax = 100,
retstart = seq_start
)
)
}
The good news...i didn't get a flat out rejection from NCBI like i did with RISMed and EUtilsGet. The bad news...it's not completing. (I get either
Error in curl::curl_fetch_memory(url, handle = handle) :
transfer closed with outstanding read data remaining
or
Error: parse error: premature EOF
(right here) ------^
I almost think there's something about using an affiliation search string in the query, because if I change the query to
query="monoclonal[Title] AND antibody[Title] AND 2010:2020[PDAT]"
it completes the run, despite having about the same number of records to deal with. So...any ideas why a particular search string would result in problems with the NCBI servers?
Is there any less complicated solution for the following task?
For working with API I need to calculate signature using the formula below.
Problem comes from double quotes in request body, they stored as \" not ".
Code below generate text 1570702210SoMeF#ke123456[{ "id": "123", "title": "foo", "version": "2019-10-10 10:10:10 } ]}SoMeF#ke123456 and correct hash is "b6e783309e9d6f8ee47647373a9f6086020b3af8" by http://www.sha1-online.com/
Signature formula:
hex( sha1({GMT_UNIXTIME} + {API_SECRET} + {CONTENT} + {API_SECRET}) ), where
hex() - function which convert binary data into hexadecimal format
sha1() - standard hash-function SHA-1, must return binary data
text string concatenation
{API_SECRET} - a secret key which is issued together with login {API_LOGIN}
{CONTENT} - request body
Following code gives incorrect signature "c7a7ecbb0fd2d6eebfb378bdd061ea88d9fb2f69".
library(stringr)
library(lubridate)
library(digest)
API_SECRET <- 'SoMeF#ke123456'
mstime <- ymd_hms('2019-10-10 10:10:10')
my_id <- 123
title1 <- 'foo'
request_body_json <- paste0('[{ "id": "', my_id,'", "title": "', title1, '", "version": "', mstime, ' } ]}')
rbj1 <- paste0(round(as.numeric(mstime)), API_SECRET, request_body_json, API_SECRET)
signature <- digest(rbj1, algo = "sha1")
I see a workaround with saving string to file with cat() function and calculate signature from file, that gives correct signature "b6e783309e9d6f8ee47647373a9f6086020b3af8"
cat(paste0(round(as.numeric(mstime)), API_SECRET, request_body_json, API_SECRET), file = 'rbj.txt')
signature <- digest('rbj.txt', algo = "sha1", file = TRUE)
Prevent the input being serialized:
digest(rbj1, algo = "sha1", serialize = FALSE)
[1] "b6e783309e9d6f8ee47647373a9f6086020b3af8"
I'm trying to access Bitfinex via api but struggling to properly authenticate my request. There is a Python example of what I want to do (https://gist.github.com/jordanbaucke/5812039) but I can't seem to get it to work in R.
key <- c("MY API KEY")
secret = c("MY API SECRET")
req <- GET("https://api.bitfinex.com/v1/balances",
authenticate(key, secret))
add_headers(X-BFX-APIKEY = key))
stop_for_status(req)
content(req)
Can someone tell me what I'm doing wrong?
/v1/balances is a Bitfinex authenticated endpoints, thus it requires the POST request with a proper handling of payload and headers.
Here is a working example from my own script:
library(httr)
key <- "..."
secret <- "..."
# payload JSON object, the request should refer to the URL
# nonce should always be greater than for previous calls
payload_json <- list(request = '/v1/account_infos', nonce = as.character(as.numeric(as.POSIXct(Sys.time()))))
# creating string from JSON payload
payload <- jsonlite::toJSON(payload_json, auto_unbox = TRUE)
# encoding payload string
payload_str <- base64enc::base64encode(charToRaw(as.character(payload)))
# adding three Bitfinex headers:
# X-BFX-APIKEY = key
# X-BFX-PAYLOAD = base64 encoded payload string
# X-BFX-SIGNATURE = sha384 encrypted payload string with the secret key
req <- POST("https://api.bitfinex.com/v1/account_infos",
add_headers('X-BFX-APIKEY' = key,
'X-BFX-PAYLOAD' = payload_str,
'X-BFX-SIGNATURE' = openssl::sha384(payload_str, key = secret))
)
content(req)
For creating "New Order" you only need to change the payload to something, like this:
payload_json <- list(request = '/v1/account_infos',
nonce = as.character(as.numeric(as.POSIXct(Sys.time()))),
symbol = 'BTCUSD',
amount = '0.3',
price = '1000',
exchange = 'bitfinex',
side = 'sell',
type = 'exchange market'
)
The rest of the code will work without changes.
For list of payload parameters check the Bitfinex API docs, e.g. "New Order".