httrパッケージでJSON形式のリクエストを送るときは、body
に送りたい内容を、encode
に"json"
を指定します。
たとえばこんな感じです。
httr::POST("example.com", body = list(id = 1), encode = "json")
このとき、bodyに渡されたリストは最終的にどのようにJSONに変換されるのか気になったのでメモ。
ソースを読む
httr::VERB()
のこの行でbody_config()
という関数が呼ばれています。
httr/http-verb.R at 7261a525ede1beb9880d1ce2e2009d27c8e8bef7 · hadley/httr · GitHub
body_config()
を見ると、encode="json"
のときにbody
に対して行われる操作は2つだけです。
httr/body.R at master · hadley/httr · GitHub
compact()
でNULL
の要素を取り除く(これはencode="json"
以外でも同じ)。compact()
の定義はここ:httr/utils.r at bdafe6d736ac977cd0a4230044688a64073ad9bb · hadley/httr · GitHubjsonlite::toJSON(x, auto_unbox = TRUE)
でJSONに変換。
ポイント1:NULLは取り除かれる
勝手に取り除いてくれるので、NULLな要素もとりあえずリストに突っ込んでしまって問題ありません。
some_api <- function(param1 = NULL, param2 = NULL, param3 = NULL) { httr::GET("example.com", body = list( param1 = param1, param2 = param2, param3 = param3 ), encode = "json") }
という関数をつくれば、
some_api(param1 = 1)
とやれば{"param1": 1}
が、some_api(param2 = 2, param3 = 4)
とやれば{"param2": 2, "param3": 4}
というように、指定したパラメータだけが送られるようにできます。
ポイント2: unboxしたくないやつにはI()
を使う
たとえば、こんな感じのリクエストを送りたいとします。
{ "id": 1, "values": [1, 2, 3, 4] }
これは、何も考えずに同じものをlistで書けばうまくいきます。
library(jsonlite) toJSON(list(id = 1, values = c(1,2,3,4)), auto_unbox = TRUE) #> {"id":1,"values":[1,2,3,4]}
しかし、values
の長さが1のときは、valuesの方まで勝手にunboxされてしまうので困ります。
toJSON(list(id = 1, values = 1), auto_unbox = TRUE) #> {"id":1,"values":1}
こういうときは、I()
で囲むとunboxされなくなります。
toJSON(list(id = 1, values = I(1)), auto_unbox = TRUE) #> {"id":1,"values":[1]}
ちなみに、httr:::body_config()
の中ではauto_unbox = TRUE
が埋め込まれているのでこの方法しかないですが、自分でJSONを組み立てるときは、逆にauto_unbox = FALSE
にして明示的にunbox()
するという手もあります。
toJSON(list(id = unbox(1), values = 1), auto_unbox = FALSE) #> {"id":1,"values":[1]}