Search code examples
rresttodoist

Use parameter in REST API Call in R


Edit: Margusl's answer worked perfectly! Thanks very much Margus, I was not aware that httr had been replaced by httr2 as I seem to have been following an outdated tutorial. Thanks for taking the time to explain!!

I am trying to call a REST API in R and having difficulty with a parameter.

The API is from Todoist, a todo list/task manager (documentation here). My goal is to collect a set number of completed tasks for documentation.

I am able to connect to the API and retrieve data.

The issue is that, by default, the API returns 30 completed tasks. Using curl in cmd prompt, \ -d limit=200 can be added to the end to change the limit to 200 tasks, and I am indeed able to do so. For example, the following code in cmd produces the desired result of 200 tasks: curl https://api.todoist.com/sync/v9/completed/get_all \ -H "Authorization: Bearer 000api_key000" \ -d limit=200

In R, however, I cannot figure out how to do it. I have tried multiple combinations of adding limit = 200 with add_header() or paste() with no success. Fundamentally, I am missing something about how to transfer the curl -d argument into an acceptable argument in R.

Below is my code that successfully gets 30 completed tasks (with my API key removed). Any advice on how to pass on the API's limit parameter as described above would be very much appreciated.

library(httr)
library(jsonlite)

raw.result <- GET(url = "https://api.todoist.com", 
                  path = "/sync/v9/completed/get_all", 
                  add_headers(Authorization=paste("Bearer 000api_key000")))

Solution

  • When there's -d / --data in a curl command, it's actually a POST call with form data (i.e. it will not work with httr::GET() )

    httr2, the successor to httr, comes with curl_translate() tool that tries to translate curl commands for you, the result is often bit raw, but should give you the right direction:

    httr2::curl_translate('curl https://api.todoist.com/sync/v9/completed/get_all \ -H "Authorization: Bearer 000api_key000" \ -d limit=200')
    #> request("https://api.todoist.com/sync/v9/completed/get_all") %>% 
    #>   req_headers(
    #>     Authorization = "Bearer 000api_key000",
    #>   ) %>% 
    #>   req_body_raw("limit=200", "application/x-www-form-urlencoded") %>% 
    #>   req_perform()
    

    To check what would be sent to the server, we can temporarily replace req_perform() with req_dry_run():

    library(httr2)
    request("https://api.todoist.com/sync/v9/completed/get_all") |>
      req_headers(
        Authorization = "Bearer 000api_key000",
      ) |>
      req_body_raw("limit=200", "application/x-www-form-urlencoded") |>
      req_dry_run()
    #> POST /sync/v9/completed/get_all HTTP/1.1
    #> Host: api.todoist.com
    #> User-Agent: httr2/0.2.3 r-curl/5.1.0 libcurl/8.3.0
    #> Accept: */*
    #> Accept-Encoding: deflate, gzip
    #> Authorization: <REDACTED>
    #> Content-Type: application/x-www-form-urlencoded
    #> Content-Length: 9
    #> 
    #> limit=200
    

    And as there are proper methods for bearer token and form body, one could write that same request as:

    request("https://api.todoist.com/sync/v9/completed/get_all") |>
      req_auth_bearer_token("000api_key000") |>
      req_body_form(limit = 200) |>
      req_dry_run()
    #> POST /sync/v9/completed/get_all HTTP/1.1
    #> Host: api.todoist.com
    #> User-Agent: httr2/0.2.3 r-curl/5.1.0 libcurl/8.3.0
    #> Accept: */*
    #> Accept-Encoding: deflate, gzip
    #> Authorization: <REDACTED>
    #> Content-Type: application/x-www-form-urlencoded
    #> Content-Length: 9
    #> 
    #> limit=200
    

    If you need some help translating to httr, there's also https://curlconverter.com/r/ , which would return:

    require(httr)
    
    headers = c(
      `Authorization` = "Bearer 000api_key000",
      `Content-Type` = "application/x-www-form-urlencoded"
    )
    
    data = list(
      `limit` = "200"
    )
    
    res <- httr::POST(url = "https://api.todoist.com/sync/v9/completed/get_all", httr::add_headers(.headers=headers), body = data, encode = "form")