Skip to contents

json_write() renders an R object as JSON text. json_write_raw() returns the same JSON as UTF-8 bytes, which is the form an HTTP request body wants.

Usage

json_write(x, pretty = FALSE, auto_unbox = TRUE)

json_write_raw(x, pretty = FALSE, auto_unbox = TRUE)

Arguments

x

The R object to serialize.

pretty

Whether to indent the output. FALSE (the default) writes the compact form, which is what you want for a request body.

auto_unbox

Whether a length-1 atomic vector becomes a bare JSON scalar (TRUE, the default) or a one-element array. Wrap a value in I() to keep it an array under auto_unbox = TRUE; that is the escape hatch for an API field that must always be a list.

Value

json_write() returns a length-1 character vector holding the JSON text. json_write_raw() returns the same document as a raw vector of UTF-8 bytes, which is what an HTTP request body wants, so that direction needs no conversion step.

Type mapping

RJSON
NULLnull
NA, NaN, Infnull
list(a = 1, b = 2){"a":1,"b":2}
list(1, 2)[1,2]
c(a = 1, b = 2){"a":1,"b":2}
1:3[1,2,3]
"a""a" (see auto_unbox)
I("a")["a"]
factorits level, as a string
Date"YYYY-MM-DD"
POSIXct"YYYY-MM-DDTHH:MM:SSZ", in UTC
data.framearray of one object per row
list()[]
structure(list(), names = character()){}

A vector or list becomes a JSON object when every element is named, and an array otherwise. Partial names would produce keys like "", which is valid JSON but almost never intended, so a partially named vector is written as an array and its names are dropped.

Data frames are written row-oriented, because that is what an HTTP API means by a table. To get the column-oriented form instead, strip the class first: json_write(as.list(df)).

Every kind of missing value becomes null: JSON has no NA, and NaN and Infinity are not JSON either. POSIXct is always written as UTC no matter what its tzone says, since it is the same instant either way, and sub-second parts are dropped. Both are doubles in R and so reach much further than a timestamp can be written: outside 0000-01-01 to 9999-12-31, the four-digit years ISO 8601 allows, they raise a zujson_write_error rather than print a year no API can parse.

A string whose Encoding() is "bytes" also raises a zujson_write_error. That marking is R saying it does not know the encoding, and JSON text is UTF-8 by definition, so there is nothing to convert from. Every other encoding R tracks is converted on the way out.

Doubles are written compactly and always read back as the same number, so 0.1 is 0.1 rather than 0.10000000000000001. A double that is a whole number is written without a decimal point at all — R has no integer literal, so 1 is a double, and 1.0 is rejected by a schema expecting an integer.

Complex vectors, raw vectors, functions, environments and POSIXlt have no sensible JSON form and raise a zujson_unsupported_type error rather than being guessed at. (POSIXlt is a list of 11 broken-down time fields; convert it with as.POSIXct() first.) A vector carrying an unrecognised class is written as its underlying type, which for a matrix means its values in column-major order with dim dropped — matrices are not turned into nested arrays in this version.

See also

json_parse() for the other direction.

Examples

json_write(list(name = "ada", ids = 1:3, ok = TRUE))
#> [1] "{\"name\":\"ada\",\"ids\":[1,2,3],\"ok\":true}"

# length-1 vectors unbox by default; I() keeps them arrays
json_write(list(tag = "x", tags = I("x")))
#> [1] "{\"tag\":\"x\",\"tags\":[\"x\"]}"

# every atomic vector stays an array
json_write(list(tag = "x"), auto_unbox = FALSE)
#> [1] "{\"tag\":[\"x\"]}"

cat(json_write(list(a = 1, b = list(c = 2)), pretty = TRUE))
#> {
#>   "a": 1,
#>   "b": {
#>     "c": 2
#>   }
#> }

json_write(data.frame(id = 1:2, nm = c("a", "b")))
#> [1] "[{\"id\":1,\"nm\":\"a\"},{\"id\":2,\"nm\":\"b\"}]"

# bytes, ready to be an HTTP request body
json_write_raw(list(q = "search"))
#>  [1] 7b 22 71 22 3a 22 73 65 61 72 63 68 22 7d