Search code examples
rpostrvesthttr

Multiple query with httr::POST


Good morning all,

I new to R and I am trying to get several from a httr::POST function. Below I send the code:

`token <- "FC9439DCA5A64714XXXXXXXXXXXXX"
url <- "https://redcap.fmrp.usp.br/api/"
formData <- list("token"=token,
    content='surveyLink',
    format='xml',
    instrument= "qualidade_de_vida_cervical",
    event= "baseline_arm_1",
    record= "1",
    returnFormat='xml'
)
response <- httr::POST(url, body = formData, encode = "form")
result <- httr::content(response)
result <- minimal_html(result) %>% html_elements("body") %>% html_text2()
return(result)`

The code works fine if I perform one request at a times. However, I had several IDs that I need to get the link.

When I try to substitute the values of "instrument","event" and "record" in order to try to execute a loop or a apply-like function I get an error message.

The code I tried:

 my_list <- c("949_1","949_2")
    
    for (i in my_list){
    token <- "FC9439DCA5A64XXXXXXXXXXXXXXXX"
    url <- "https://redcap.fmrp.usp.br/api/"
    formData <- list("token"=token,
        content='surveyLink',
        format='xml',
        instrument= "qualidade_de_vida_cervical",
        event= "baseline_arm_1",
        record= my_list,
        returnFormat='xml'
    )
    response <- httr::POST(url, body = formData, encode = "form")
    result <- httr::content(response)
    result <- minimal_html(result) %>% html_elements("body") %>% html_text2()
    return(result) 
    }

The error I get:

"Error in vapply(elements, encode, character(1)) : values must be length 1, but FUN(X[[6]]) result is length 2"

The traceback to error is as follow:
6. vapply(elements, encode, character(1))
5. compose_query(body)
4. body_raw(compose_query(body), "application/x-www-form-urlencoded")
3. body_config(body, match.arg(encode))
2. request_build("POST", hu$url, body_config(body, match.arg(encode)), 
as.request(config), ...)
1. httr::POST(url, body = formData, encode = "form")

My question is, is that possible to retrieve a batch of those links with an iterative function?

Thank you very much,

Gabriel Pokorny


Solution

  • (Up front: unverified, I don't have a token for that API.)

    Two things I'm fixing:

    1. for loops don't return anything, and you are overwriting result each pass through the loop. There are two remedies for this, either using lapply instead of a for loop or pre-instantiating a list first and filling each element. I'll show both.

    2. Even though it looks like you intend to iterate over my_list, a vector of record IDs, you are passing the whole vector in all calls, likely a mistake. Let's iterate over my_list and use it everywhere.

    First, the use of lapply which is (imo) a clean and easy way to go:

    token <- "FC9439DCA5A64714XXXXXXXXXXXXX"
    url <- "https://redcap.fmrp.usp.br/api/"
    my_list <- c("949_1","949_2")
    
    out <- lapply(my_list, function(one_record) {
      formData <- list(token=token,
                       content='surveyLink',
                       format='xml',
                       instrument= "qualidade_de_vida_cervical",
                       event= "baseline_arm_1",
                       record= one_record,
                       returnFormat='xml'
                       )
      response <- httr::POST(url, body = formData, encode = "form")
      if (httr::status_code(response) == 200L) {
        httr::content(response) %>%
          minimal_html() %>%
          html_elements("body") %>%
          html_text2()
      } # else NULL
    })
    

    If you prefer the for loop (it may have some advantages, some subjective), then do this instead:

    out <- list()
    for (i in seq_along(my_list)) {
      one_record <- my_list[[i]]
      formData <- list(token=token,
                       content='surveyLink',
                       format='xml',
                       instrument= "qualidade_de_vida_cervical",
                       event= "baseline_arm_1",
                       record= one_record,
                       returnFormat='xml'
                       )
      response <- httr::POST(url, body = formData, encode = "form")
      if (httr::status_code(response) == 200L) {
        out[[i]] <- httr::content(response) %>%
          minimal_html() %>%
          html_elements("body") %>%
          html_text2()
      } # else NULL
    }