読者です 読者をやめる 読者になる 読者になる

メモ:httrのVERB関数の引数に指定できるもの

たとえばGET()はこんな感じ。urlはいいとして、config...が謎。

packageVersion("httr")
#> [1] ‘1.2.1’

httr::GET
#> function (url = NULL, config = list(), ..., handle = NULL) 
#> {
#>     hu <- handle_url(handle, url, ...)
#>     req <- request_build("GET", hu$url, as.request(config), ...)
#>     request_perform(req, hu$handle$handle)
#> }
#> <environment: namespace:httr>

configのドキュメントはこうなっている。

Additional configuration settings such as http authentication (authenticate), additional headers (add_headers), cookies (set_cookies) etc. See config for full details and list of helpers.

...のドキュメントはこう。

Further named parameters, such as query, path, etc, passed on to modify_url. Unnamed parameters will be combined with config.

handle_url

...のうち名前付きの引数だけが使われる(named()が名前付き引数だけ取り出す関数らしい)

handle_url <- function(handle = NULL, url = NULL, ...) {
  if (is.null(url) && is.null(handle)) {
    stop("Must specify at least one of url or handle")
  }

  if (is.null(handle))  handle <- handle_find(url)
  if (is.null(url))     url <- handle$url

  # If named components in ..., modify the url
  new <- named(list(...))
  if (length(new) > 0 || is.url(url)) {
    old <- parse_url(url)
    url <- build_url(utils::modifyList(old, new))
  }

  list(handle = handle, url = url)
}

(https://github.com/hadley/httr/blob/7261a525ede1beb9880d1ce2e2009d27c8e8bef7/R/handle-url.r#L1-L17)

request_build

こっちは逆に、...のうち名前がついていないものだけが使われる。(has_name()TRUEになるものはextraから除外されるらしい)

request_build <- function(method, url, ...) {
  extra <- list(...)
  extra[has_name(extra)] <- NULL

  req <- Reduce(request_combine, extra, init = request())

  req$method <- method
  req$url <- url

  req
}

(https://github.com/hadley/httr/blob/1647b0a02fe6504384f5a5dbd5643083e267f2d8/R/request.R#L55-L65)

as.request

config引数はas.request(config)として使われている。as.request()の関数定義は以下のようになっている。

as.request <- function(x) UseMethod("as.request")
as.request.list <- function(x) structure(x, class = "request")
as.request.request <- function(x) x
as.request.NULL <- function(x) request()
as.request.Token <- function(x) request(auth_token = x)

(https://github.com/hadley/httr/blob/1647b0a02fe6504384f5a5dbd5643083e267f2d8/R/request.R#L49-L53)

ということで、configとして指定できるのは

  • list
  • request
  • Token

のどれか。ちなみにTokenの場合は最終的にこういう感じでsign()メソッドが呼び出される。

 signed_req <- token$sign(req$method, req$url)

(https://github.com/hadley/httr/blob/1647b0a02fe6504384f5a5dbd5643083e267f2d8/R/request.R#L115)

Token2.0だとas_headerというパラメータに応じて、Authorizationというヘッダになるかaccess_tokenというクエリパラメータになる。LinkedInの例のように自前でsign()を定義することも可能。

ヘッダとかトークンとかは名前なし引数かconfigとして渡さないといけない

例1: Content-Typeヘッダ

うっかりheaders=とかつけてしまうと反映されない。名前をつけるとhandle_url(...)の中でbuild_url(url)に渡されるけど、そこではurlからurl$schemaとか必要なものだけを取り出していて、余分なものがあっても特にエラーになったりしない。単純に無視される。

# これはOK
GET("http://httpbin.org/headers", content_type_json())

# これもOK
GET("http://httpbin.org/headers", config = content_type_json())

# これはNG
GET("http://httpbin.org/headers", headers = content_type_json())

例2: OAuthトークン

トークンはちょっと扱いが別なのでconfig()token引数として指定することもできる。

# これはOK
GET("http://example.com", mytoken)

# これもOK
GET("http://example.com", config = mytoken)

# これもOK
GET("http://example.com", config = config(token = mytoken))

# でもこれはNG
GET("http://example.com", token = mytoken)

たぶん、config引数にはひとつだけしか指定できないので、名前なし引数で指定する方が並べて書くことができて便利な気がする。

request同士はc()で合成することができるので、Tokenrequestに手動で変換しておけばあらかじめconfigオブジェクトをつくっておくことはできる。

cfg <- c(content_type_json(), httr:::as.request.Token(mytoken))
cfg
#> <request>
#> Headers:
#> * Content-Type: application/json
#> Auth token: Token2.0

GET(url, config = cfg)

という感じ。

でも、httrのデモではconfig引数にconfig(token = token)を指定しているからこれがいいのかな…

github.com