bs-json v1.0.1
bs-json
Experimental JSON encode/decode library for BuckleScript.
NOTE: NPM package has moved to @glennsl/bs-json. Remember to update both package.json AND bsconfig.json.
The Decode module in particular provides a basic set of decoder functions to be composed into more complex decoders. A
decoder is a function that takes a Js.Json.t and either returns a value of the desired type if successful or raises a
DecodeError exception if not. Other functions accept a decoder and produce another decoder. Like array, which when
given a decoder for type t will return a decoder that tries to produce a value of type t array. So to decode an
int array you combine Json.Decode.int with Json.Decode.array into Json.Decode.(array int). An array of arrays of
ints? Json.Decode.(array (array int)). Dict containing arrays of ints? Json.Decode.(dict (array int)).
Example
(* OCaml *)
type line = {
start: point;
end_: point;
thickness: int option
}
and point = {
x: float;
y: float
}
module Decode = struct
let point json =
let open! Json.Decode in {
x = json |> field "x" float;
y = json |> field "y" float
}
let line json =
Json.Decode.{
start = json |> field "start" point;
end_ = json |> field "end" point;
thickness = json |> optional (field "thickness" int)
}
end
let data = {| {
"start": { "x": 1.1, "y": -0.4 },
"end": { "x": 5.3, "y": 3.8 }
} |}
let line = data |> Json.parseOrRaise
|> Decode.line/* Reason */
type line = {
start: point,
end_: point,
thickness: option(int)
}
and point = {
x: float,
y: float
};
module Decode = {
let point = json =>
Json.Decode.{
x: json |> field("x", float),
y: json |> field("y", float)
};
let line = json =>
Json.Decode.{
start: json |> field("start", point),
end_: json |> field("end", point),
thickness: json |> optional(field("thickness", int))
};
};
let data = {| {
"start": { "x": 1.1, "y": -0.4 },
"end": { "x": 5.3, "y": 3.8 }
} |};
let line = data |> Json.parseOrRaise
|> Decode.line;See examples for more.
Installation
npm install --save bs-jsonThen add bs-json to bs-dependencies in your bsconfig.json:
{
...
"bs-dependencies": ["bs-json"]
}Documentation
API
For the moment, please see the interface files:
Writing custom decoders and encoders
If you look at the type signature of Js.Decode.array, for example, you'll see it takes an 'a decoder and returns an
'a array decoder. 'a decoder is just an alias for Js.Json.t -> 'a, so if we expand the type signature of array
we'll get (Js.Json.t -> 'a) -> Js.Json.t -> 'a array. We can now see that it is a function that takes a decoder and
returns a function, itself a decoder. Applying the int decoder to array will give us an int array decoder, a
function Js.Json.t -> int array.
If you've written a function that takes just Js.Json.t and returns user-defined types of your own, you've already been
writing composable decoders! Let's look at Decode.point from the example above:
let point json =
let open! Json.Decode in {
x = json |> field "x" float;
y = json |> field "y" float
}This is a function Js.Json.t -> point, or a point decoder. So if we'd like to decode an array of points, we can just
pass it to Json.Decode.array to get a point array decoder in return.
Builders
To write a decoder builder like Json.Decode.array we need to take another decoder as an argument, and thanks to
currying we just need to apply it where we'd otherwise use a fixed decoder. Say we want to be able to decode both
int points and float points. First we'd have to parameterize the type:
type 'a point = {
x: 'a,
y: 'a
}Then we can change our point function from above to take and use a decoder argument:
let point decodeNumber json =
let open! Json.Decode in {
x = json |> field "x" decodeNumber;
y = json |> field "y" decodeNumber
}And if we wish we can now create aliases for each variant:
let intPoint = point Json.Decode.int
let floatPoint = point Json.Decode.floatEncoders
Encoders work exactly the same way, just in reverse. 'a encoder is just an alias for 'a -> Js.Json.t, and this also
transfers to composition: 'a encoder -> 'a array encoder expands to ('a -> Js.Json.t) -> 'a array -> Js.Json.t.
Changes
1.0.1
- Moved repository from
reasonml-community/bs-jsontoglennsl/bs-json - Renamed NPM package from
bs-jsonto@glennsl/bs-json
1.0.0
- Replaced
Json.Encoder.arraywithJson.Encode.arrayOfrenamed toarray. DeprecatedarrayOfalias. - Added
Json.parse,Json.parseOrRaise,Json.stringify - Added
dateencoder and decoder - Added
tuple2/tuple3/tuple4encoders and decoders - Fixed bug where js integers > 32-bit were rejected as integers by Json.Decode.int (#15)
0.2.4
- Added
Json.Encode.bool - Added
Json.Encode.pair - Added
Json.Encode.withDefault - Added
Json.Encode.nullable - Added
Json.Encode.arrayOf - Added
Json.Encode.jsonArrayas replacement forJson.Encode.array - Deprecated
Json.Encode.array
0.2.3
- Fixed embarrassing bug where an API was used that isn't available on IE (honestly more embarrassed on behalf of IE though)
0.2.2
- Added
Json.Decode.pair
0.2.1
- Added
Json.Encode.list
0.2.0
- Breaking: Renamed
Json.Encode.object_toJson.Encode.dict - Added
Json.Encode.object_taking a list of properties instead of a Json.Dict.t as before