Skip to content

Commit

Permalink
docs: update docs for record decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
mlms13 committed Oct 15, 2023
1 parent 3ddb408 commit 0275dd5
Showing 1 changed file with 5 additions and 44 deletions.
49 changes: 5 additions & 44 deletions docs/decoding-objects.md
Expand Up @@ -53,9 +53,9 @@ let make = (name, age, isAdmin, lastLogin) =>

...the real goal of `bs-decode` is to give you the tools you need to build up complex record types (like this one) from JSON. You can certainly use `field` and `optionalField` to piece these things together, but the following approaches will make your life easier.

### Let-Ops (Coming Soon)
### Let-Ops

In the very near future, `bs-decode` will be switching from BuckleScript to Melange. This will give us access to newer OCaml features, such as [binding operators](https://v2.ocaml.org/manual/bindingops.html). This dramatically simplifies the syntax for decoding and constructing complex objects:
With the switch to Melange, `bs-decode` now has access to newer OCaml features, such as [binding operators](https://v2.ocaml.org/manual/bindingops.html). This dramatically simplifies the syntax for decoding and constructing complex objects:

```reasonml
let decode = {
Expand All @@ -64,15 +64,15 @@ let decode = {
and+ age = field("age", intFromNumber)
and+ isAdmin = field("isAdmin", boolean)
and+ lastLogin = optionalField("lastLogin", date);
User.make(name, age, isAdmin, lastLogin);
{ name, age, isAdmin, lastLogin };
};
```

Once available, this will replace the "Pipeline" decoding (see below). Unlike the other strategies outlined below, the order of the field decoders doesn't matter. It's much easier to see how each field is used in the constructor, and it works with labeled functions and literal record construction.
This is the preferred method of decoding JSON into Reason records, as it allows constructing tuples, records, and calling functions with labeled arguments.

### Haskell Validation Style

It's also possible to use `map` and `apply` functions (often in their infix form `<$>` and `<*>`) to build up a larger decoder from smaller ones. This style my look more familiar if you've used validation libraries in Haskell.
It's also possible to use `map` and `apply` functions (often in their infix form `<$>` and `<*>`) to build up a larger decoder from smaller ones. This style my look more familiar if you've used validation libraries in Haskell. Importantly, this will not work if `User.make` expects labeled arguments, and it's important to decode the fields in the same order that `User.make` expects to receive its arguments.

```reasonml
let ((<$>), (<*>)) = Decode.(map, apply);
Expand All @@ -86,42 +86,3 @@ let decode =
<*> optionalField("lastLogin", date)
);
```

### Combining Decoders with `mapN`

The provided `map2`...`map5` functions can be used to take the results of up to 5 decoders and combine them using a function that receives the up-to-5 values if all decoders succeed. This is simple to use, but obviously limiting if the record you want to construct has more than 5 fields.

```reasonml
let decode =
Decode.(
map4(
User.make,
field("name", string),
field("age", intFromNumber),
field("isAdmin", boolean),
optionalField("lastLogin", date),
)
);
```

### Pipeline-Style (Deprecated)

**Note:** This style of decoding has been deprecated and will be removed in v2.0.

Given the `user` type above and its `make` function, you can build up a record by decoding each field in a style inspired by the [Elm Decode Pipeline](https://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/3.0.1/) library for Elm.

The order of decoded fields is significant, as the pipeline leverages the partial application of the `make` function. Each `field` or `optionalField` line in the example below fills in the next available slot in the `make` function.

```reasonml
let decode = json =>
Decode.Pipeline.(
succeed(make)
|> field("name", string)
|> field("age", intFromNumber)
|> field("isAdmin", boolean)
|> optionalField("lastLogin", date)
|> run(json)
);
```

Unlike other decode functions we've looked at, the Pipeline style is not eager. Instead, nothing will be decoded until the whole pipeline is executed by using the `run` function with the appropriate JSON.

0 comments on commit 0275dd5

Please sign in to comment.