Recology

R/etc.

request - a high level HTTP client for R

    R api http DSL httr
 Source: .Rmd/.md

request is DSL for http requests for R, and is inspired by the CLI tool httpie. It’s built on httr.

The following were driving principles for this package:

The following is a brief demo of some of the package functionality:

Install

From CRAN

install.packages("request")

Or from GitHub

devtools::install_github("sckott/request")
library("request")

Execute on last pipe

When using pipes (%>%) in request, we autodetect last piped command, and execute http() if it’s the last. If not the last, the output gets passed to the next command, and so on. This feature (and magrittr) were done by Stefan Milton Bache.

This feature is really nice because a) it’s one less thing you need to do, and b) you only need to care about the request itself.

You can escape auto-execution if you use the function peep(), which prints out a summary of the request you’ve created, but does not execute an HTTP request.

HTTP Requests

A high level function http() wraps a lower level R6 object RequestIterator, which holds a series of variables and functions to execute GET and POST requests, and will hold other HTTP verbs as well. In addition, it can hold state, which will allow us to do paging internally for you (see below). You have direct access to the R6 object if you call http_client() instead of http().

NSE and SE

Most if not all functions in request support non-standard evaluation (NSE) as well as standard evaluation (SE). If a function supports both, there’s a version without an underscore for NSE, while a version with an underscore is for SE. For example, here, we make a HTTP request by passing a base URL, then a series of paths that get combined together. First the NSE version

api('https://api.github.com/') %>%
  api_path(repos, ropensci, rgbif, issues)

Then the SE version

api('https://api.github.com/') %>%
  api_path_('repos', 'ropensci', 'rgbif', 'issues')

Building API routes

The first thing you’ll want to do is lay out the base URL for your request. The function api() is your friend.

api() works with full or partial URLs:

api('https://api.github.com/')
#> URL: https://api.github.com/
api('http://api.gbif.org/v1')
#> URL: http://api.gbif.org/v1
api('api.gbif.org/v1')
#> URL: api.gbif.org/v1

And works with ports, full or partial

api('http://localhost:9200')
#> URL: http://localhost:9200
api('localhost:9200')
#> URL: http://localhost:9200
api(':9200')
#> URL: http://localhost:9200
api('9200')
#> URL: http://localhost:9200
api('9200/stuff')
#> URL: http://localhost:9200/stuff

Make HTTP requests

The above examples with api() are not passed through a pipe, so only define a URL, but don’t do an HTTP request. To make an HTTP request, you can either pipe a url or partial url to e.g., api(), or call http() at the end of a string of function calls:

'https://api.github.com/' %>% api()
#> $current_user_url
#> [1] "https://api.github.com/user"
#>
#> $current_user_authorizations_html_url
#> [1] "https://github.com/settings/connections/applications{/client_id}"
#>
#> $authorizations_url
#> [1] "https://api.github.com/authorizations"
#>
#> $code_search_url
...

Or

api('https://api.github.com/') %>% http()
#> $current_user_url
#> [1] "https://api.github.com/user"
#>
#> $current_user_authorizations_html_url
#> [1] "https://github.com/settings/connections/applications{/client_id}"
#>
#> $authorizations_url
#> [1] "https://api.github.com/authorizations"
#>
#> $code_search_url
...

http() is called at the end of a chain of piped commands, so no need to invoke it. However, you can if you like.

Templating

repo_info <- list(username = 'craigcitro', repo = 'r-travis')
api('https://api.github.com/') %>%
  api_template(template = 'repos///issues', data = repo_info)
#> [[1]]
#> [[1]]$url
#> [1] "https://api.github.com/repos/craigcitro/r-travis/issues/164"
#>
#> [[1]]$labels_url
#> [1] "https://api.github.com/repos/craigcitro/r-travis/issues/164/labels{/name}"
#>
#> [[1]]$comments_url
#> [1] "https://api.github.com/repos/craigcitro/r-travis/issues/164/comments"
#> ...

Set paths

api_path() adds paths to the base URL

api('https://api.github.com/') %>%
  api_path(repos, ropensci, rgbif, issues) %>%
  peep
#> <http request>
#>   url: https://api.github.com/
#>   paths: repos/ropensci/rgbif/issues
#>   query:
#>   body:
#>   paging:
#>   headers:
#>   rate limit:
#>   retry (n/delay (s)): /
#>   error handler:
#>   config:

Query

api("http://api.plos.org/search") %>%
  api_query(q = ecology, wt = json, fl = journal) %>%
  peep
#> <http request>
#>   url: http://api.plos.org/search
#>   paths:
#>   query: q=ecology, wt=json, fl=journal
#>   body:
#>   paging:
#>   headers:
#>   rate limit:
#>   retry (n/delay (s)): /
#>   error handler:
#>   config:

Headers

api('http://httpbin.org/headers') %>%
  api_headers(`X-FARGO-SEASON` = 3, `X-NARCOS-SEASON` = 5) %>%
  peep
#> <http request>
#>   url: http://httpbin.org/headers
#>   paths:
#>   query:
#>   body:
#>   paging:
#>   headers:
#>     X-FARGO-SEASON: 3
#>     X-NARCOS-SEASON: 5
#>   rate limit:
#>   retry (n/delay (s)): /
#>   error handler:
#>   config:

curl configuration

httr is exported in request, so you can use httr functions like verbose() to get verbose curl output

api('http://httpbin.org/headers') %>%
  api_config(verbose())
#> -> GET /headers HTTP/1.1
#> -> Host: httpbin.org
#> -> User-Agent: curl/7.43.0 curl/0.9.4 httr/1.0.0 request/0.1.0
#> -> Accept-Encoding: gzip, deflate
#> -> Accept: application/json, text/xml, application/xml, */*
#> ->
#> <- HTTP/1.1 200 OK
#> <- Server: nginx
#> <- Date: Sun, 03 Jan 2016 16:56:29 GMT
#> <- Content-Type: application/json
#> <- Content-Length: 227
#> <- Connection: keep-alive
#> <- Access-Control-Allow-Origin: *
#> <- Access-Control-Allow-Credentials: true
#> <-
#> $headers
#> $headers$Accept
#> [1] "application/json, text/xml, application/xml, */*"
#> ...

Coming soon

There’s a number of interesting features that should be coming soon to request.

comments powered by Disqus