In the below example i am using Google Maps Places API's (new) Text Search (new) request method. See here more information about this API method.
Basically i am starting to have problems when the JSON request body starts to have nested (and nasty) elements. Below i will give examples on what works and what doesn't work:
library(httr2)
# Test params:
textQuery = "nature retreat in Southwest Alentejo, Portugal"
maxResultCount = 10
key = API_KEY
params <- list(textQuery = textQuery,
maxResultCount = maxResultCount)
req <-
request("https://places.googleapis.com/v1/places:searchText") |>
req_headers(
`X-Goog-Api-Key` = key,
`X-Goog-FieldMask` = "*",
`Content-Type` = "application/json"
) |>
req_body_json(Filter(Negate(is.null), params))
req |>
req_dry_run()
# POST /v1/places: searchText HTTP/1.1
# Host: places.googleapis.com
# User-Agent: httr2/0.2.3 r-curl/5.2.1 libcurl/7.81.0
# Accept: */*
# Accept-Encoding: deflate, gzip, br, zstd
# X-Goog-Api-Key: API_KEY
# X-Goog-FieldMask: *
# Content-Type: application/json
# Content-Length: 47
#
# {"textQuery":"nature retreat in Southwest Alentejo, Portugal","maxResultCount":10}
req |>
req_perform()
# <httr2_response>
# POST https://places.googleapis.com/v1/places:searchText
# Status: 200 OK
# Content-Type: application/json
# Body: In memory (192086 bytes)
Now i am trying to add a JSON input to the JSON request body. Below i am trying to reproduce this example from the Places API, which has the following curl command:
curl -X POST -d '{
"textQuery" : "Spicy Vegetarian Food",
"openNow": true,
"maxResultCount": 10,
"locationBias": {
"circle": {
"center": {"latitude": 37.7937, "longitude": -122.3965},
"radius": 500.0
}
},
}' \
-H 'Content-Type: application/json' -H 'X-Goog-Api-Key: API_KEY' \
-H 'X-Goog-FieldMask: places.displayName,places.formattedAddress' \
'https://places.googleapis.com/v1/places:searchText'
This should be the httr2 equivalent, but it doesn't work:
# Test params:
textQuery = "Spicy Vegetarian Food"
openNow = "true"
maxResultCount = 10
latitude = 37.7937
longitude = -122.3965
radius = 500
key = API_KEY
# Creating the locationRestriction JSON parameter:
body <- list()
innerBody <- list()
innerInnerBody <- list()
innerInnerBody$latitude <- latitude
innerInnerBody$longitude <- longitude
innerBody$center <- innerInnerBody
innerBody$radius <- radius
body$circle <- innerBody
locationBias <- jsonlite::toJSON(body, auto_unbox = TRUE, pretty = TRUE)
locationBias
# {
# "circle": {
# "center": {
# "latitude": 37.7937,
# "longitude": -122.3965
# },
# "radius": 500
# }
# }
params <- list(textQuery = textQuery,
openNow = openNow,
maxResultCount = maxResultCount,
locationBias = locationBias)
params
# $textQuery
# [1] "Spicy Vegetarian Food"
#
# $openNow
# [1] "true"
#
# $maxResultCount
# [1] 10
#
# $locationBias
# {
# "circle": {
# "center": {
# "latitude": 37.7937,
# "longitude": -122.3965
# },
# "radius": 500
# }
# }
req <-
request("https://places.googleapis.com/v1/places:searchText") |>
req_headers(
`X-Goog-Api-Key` = key,
`X-Goog-FieldMask` = "*",
`Content-Type` = "application/json"
) |>
req_body_json(Filter(Negate(is.null), params))
req |>
req_dry_run()
# POST /v1/places: searchText HTTP/1.1
# Host: places.googleapis.com
# User-Agent: httr2/0.2.3 r-curl/5.2.1 libcurl/7.81.0
# Accept: */*
# Accept-Encoding: deflate, gzip, br, zstd
# X-Goog-Api-Key: API_KEY
# X-Goog-FieldMask: *
# Content-Type: application/json
# Content-Length: 228
#
# {"textQuery":"Spicy Vegetarian Food","openNow":"true","maxResultCount":10,"locationBias":"{\n \"circle\": {\n \"center\": {\n \"latitude\": 37.7937,\n \"longitude\": -122.3965\n },\n \"radius\": 500\n }\n}"}
req |>
req_perform()
# Error in `req_perform()`:
# ! HTTP 400 Bad Request.
I have double checked that by removing the locationBias
input all works fine. Any ideas why i get the 400 error in httr2 with the JSON locationBias
input?
According to curl
example, payload is a regular JSON object; as you are passing body
through jsonlite::toJSON()
and then assign it to locationBias
, it becomes a string. Note how it gets escaped in req_dry_run()
output:
# ... "locationBias":"{\n \"circle\": {\n \"center\": {\n \"latitude\": 37.7937,\n \"longitude\": -122.3965\n },\n \"radius\": 500\n }\n}"}
Without jsonlite::toJSON()
it should be fine:
library(httr2)
# Test params:
textQuery = "Spicy Vegetarian Food"
openNow = "true"
maxResultCount = 10
latitude = 37.7937
longitude = -122.3965
radius = 500
key = "API_KEY"
# Creating the locationRestriction JSON parameter:
body <- list()
innerBody <- list()
innerInnerBody <- list()
innerInnerBody$latitude <- latitude
innerInnerBody$longitude <- longitude
innerBody$center <- innerInnerBody
innerBody$radius <- radius
body$circle <- innerBody
str(body)
#> List of 1
#> $ circle:List of 2
#> ..$ center:List of 2
#> .. ..$ latitude : num 37.8
#> .. ..$ longitude: num -122
#> ..$ radius: num 500
params <- list(textQuery = textQuery,
openNow = openNow,
maxResultCount = maxResultCount,
locationBias = body)
str(params)
#> List of 4
#> $ textQuery : chr "Spicy Vegetarian Food"
#> $ openNow : chr "true"
#> $ maxResultCount: num 10
#> $ locationBias :List of 1
#> ..$ circle:List of 2
#> .. ..$ center:List of 2
#> .. .. ..$ latitude : num 37.8
#> .. .. ..$ longitude: num -122
#> .. ..$ radius: num 500
req <-
request("https://places.googleapis.com/v1/places:searchText") |>
req_headers(
`X-Goog-Api-Key` = key,
`X-Goog-FieldMask` = "*",
`Content-Type` = "application/json"
) |>
req_body_json(Filter(Negate(is.null), params))
Payload in request looks fine now:
req |>
req_dry_run()
#> POST /v1/places: searchText HTTP/1.1
#> Host: places.googleapis.com
#> User-Agent: httr2/1.0.0 r-curl/5.2.1 libcurl/8.3.0
#> Accept: */*
#> Accept-Encoding: deflate, gzip
#> X-Goog-Api-Key: API_KEY
#> X-Goog-FieldMask: *
#> Content-Type: application/json
#> Content-Length: 178
#>
#> {"textQuery":"Spicy Vegetarian Food","openNow":"true","maxResultCount":10,"locationBias":{"circle":{"center":{"latitude":37.793700000000001,"longitude":-122.3965},"radius":500}}}
Created on 2024-04-24 with reprex v2.1.0