Skip to content

Commit 1e5aeca

Browse files
Merge pull request #65 from purescript-contrib/thomashoneyman-patch-1
Fix error in tutorial suggesting .: for optional fields
2 parents 5f8ebe5 + 6372c0d commit 1e5aeca

File tree

1 file changed

+22
-23
lines changed

1 file changed

+22
-23
lines changed

README.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
[![Maintainer: garyb](https://img.shields.io/badge/maintainer-garyb-lightgrey.svg)](http://github.com/garyb)
77
[![Maintainer: thomashoneyman](https://img.shields.io/badge/maintainer-thomashoneyman-lightgrey.svg)](http://github.com/thomashoneyman)
88

9-
Argonaut is a library for working with JSON in PureScript. `argonaut-codecs` provides codecs based on the `EncodeJson` and `DecodeJson` type classes, along with instances for common data types and combinators for encoding and decoding `Json` values.
9+
[Argonaut](https://github.com/purescript-contrib/purescript-argonaut) is a collection of libraries for working with JSON in PureScript. `argonaut-codecs` provides codecs based on the `EncodeJson` and `DecodeJson` type classes, along with instances for common data types and combinators for encoding and decoding `Json` values.
1010

1111
## Installation
1212

13+
This library is bundled as part of [Argonaut](https://github.com/purescript-contrib/purescript-argonaut) and can be installed via that library. To install just `argonaut-codecs`:
14+
1315
```sh
1416
# with Spago
1517
spago install argonaut-codecs
@@ -20,9 +22,7 @@ bower install purescript-argonaut-codecs
2022

2123
## Documentation
2224

23-
Module documentation is [published on Pursuit](https://pursuit.purescript.org/packages/purescript-argonaut-codecs).
24-
25-
You may also be interested in other libraries in the Argonaut ecosystem:
25+
Module documentation is [published on Pursuit](https://pursuit.purescript.org/packages/purescript-argonaut-codecs). You may also be interested in other libraries in the Argonaut ecosystem:
2626

2727
- [purescript-argonaut-core](https://github.com/purescript-contrib/purescript-argonaut-core) defines the `Json` type, along with basic parsing, printing, and folding functions
2828
- [purescript-argonaut-traversals](https://github.com/purescript-contrib/purescript-argonaut-traversals) defines prisms, traversals, and zippers for the `Json` type.
@@ -49,7 +49,7 @@ userFromJson = decodeJson
4949

5050
In a REPL we can see these functions in action:
5151

52-
```sh
52+
```
5353
> user = { name: "Tom", age: Just 25 }
5454
> stringify (encodeJson user)
5555
"{\"name\":\"Tom\",\"age\":25}"
@@ -125,7 +125,7 @@ encodeJson :: EncodeJson a => a -> Json
125125

126126
> Tip: There is no `Show` instance for `Json`. To print a `Json` value as a valid JSON string, use `stringify` -- it's the same as the [JavaScript `stringify` method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
127127
128-
```sh
128+
```
129129
> user = { name: "Tom", age: Just 25, team: Just "Red Team" } :: User
130130
> stringify (encodeJson user)
131131
"{\"name\":\"Tom\",\"age\":25,\"team\":\"Red Team\"}"
@@ -143,7 +143,7 @@ decodeJson :: DecodeJson a => Json -> Either String a
143143

144144
> Tip: To parse a JSON string as a `Json` value, you can use the `jsonParser` function (which can fail). If you are sure you have valid JSON, then consider writing it in an FFI file and foreign importing it as `Json` as described in the [`argonaut-core` documentation](https://github.com/purescript-contrib/purescript-argonaut-core#introducing-json-values).
145145
146-
```sh
146+
```
147147
> userJsonString = """{ "name": "Tom", "age": 25, "team": null }"""
148148
> decodedUser = decodeJson =<< jsonParser userJsonString
149149
@@ -155,7 +155,7 @@ Right "{\"name\":\"Tom\",\"age\":25,\"team\":null}"
155155

156156
Decoding can fail if the `Json` doesn't match the shape expected by a `DecodeJson` instance; in that case, an error is returned instead of the decoded value.
157157

158-
```sh
158+
```
159159
> badUserJsonString = """{ "name": "Tom", "age": null }
160160
> (decodeJson =<< jsonParser badUserJsonString) :: Either String User
161161
Left "JSON was missing expected field: team"
@@ -239,7 +239,7 @@ To recap: manually encoding your data type involves a few steps:
239239
2. Use `:=` or `:=?` to create a key/value pair in a JSON object
240240
3. Use `~>` or `~>?` to chain together multiple key/value pairs.
241241

242-
Ultimately, this will produce an `Object Json` which can be serialized to a JSON string or manipulated.
242+
Ultimately, this will produce `Json` which can be serialized to a JSON string or manipulated.
243243

244244
#### Decoding JSON
245245

@@ -274,8 +274,9 @@ If your type can be represented easily with a `String`, `Number`, `Boolean`, or
274274

275275
However, quite often your data type will require representation as an object. This library provides combinators in `Data.Argonaut.Decode.Combinators` which are useful for decoding objects into PureScript types by looking up keys in the object and decoding them according to their `DecodeJson` instances.
276276

277-
- Use `.:` (`getField`) to decode a field; if the field is missing, this will decode to a `Maybe`
278-
- Use `.!=` (`defaultField`) to provide a default value for a field which may not exist. If decoding fails, you'll still get an error; if decoding succeeds with a value of type `Maybe a`, then this default value will handle the `Nothing` case.
277+
- Use `.:` (`getField`) to decode a field where the key must exist; if the field is missing, this will fail with a decoding error.
278+
- Use `.:?` (`getFieldOptional'`) to decode a field where the key may exist; if the field is missing or its value is `null` then this will return `Nothing`, and otherwise it will attempt to decode the value at the given key.
279+
- Use `.!=` (`defaultField`) in conjunction with `.:?` to provide a default value for a field which may not exist. If decoding fails, you'll still get an error; if decoding succeeds with a value of type `Maybe a`, then this default value will handle the `Nothing` case.
279280

280281
Let's use these combinators to decode a `Json` object into our `AppUser` record.
281282

@@ -284,22 +285,20 @@ The `decodeJson` function returns an `Either String a` value; `Either` is a mona
284285
```purs
285286
instance decodeJsonAppUser :: DecodeJson AppUser where
286287
decodeJson json = do
287-
obj <- decodeJson json -- decode `Json` to `Object Json`
288-
name <- obj .: "name" -- decode the "name" key to a `String`
289-
age <- obj .: "age" -- decode the "age" key to a `Maybe Int`
290-
team <- obj .: "team" .!= RedTeam -- decode "team" to `Team`, defaulting to `RedTeam`
291-
-- if the field is missing or `null`
288+
obj <- decodeJson json -- decode `Json` to `Object Json`
289+
name <- obj .: "name" -- decode the "name" key to a `String`
290+
age <- obj .:? "age" -- decode the "age" key to a `Maybe Int`
291+
team <- obj .:? "team" .!= RedTeam -- decode "team" to `Team`, defaulting to `RedTeam`
292+
-- if the field is missing or `null`
292293
pure $ AppUser { name, age, team }
293294
```
294295

295296
To recap: manually decoding your data type involves a few steps:
296297

297298
1. Ensure that all types you are decoding have a `DecodeJson` instance
298-
299-
2. Use `.:` to decode object fields
300-
299+
2. Use `.:` to decode object fields where the key must exist
300+
3. Use `.:?` to decode object fields where the key may exist or its value may be null
301301
3. Use `.!=` to provide a default value for fields which may exist in the `Json`, but must exist in the type you're decoding to (it's like `fromMaybe` for your decoder, unwrapping the decoded value).
302-
303302
4. It's common to use the `Either` monad for convenience when writing decoders. Any failed decoding step will abort the entire computation with that error. See [Solving Common Problems](#solving-common-problems) for alternative approaches to decoding.
304303

305304
#### Deriving Instances
@@ -479,14 +478,14 @@ decodeUser :: Json -> Either String User
479478
decodeUser json = do
480479
obj <- decodeJson json
481480
name <- obj .: "name"
482-
age <- obj .: "age"
481+
age <- obj .:? "age"
483482
location <- obj .: "location"
484483
pure $ User { name, age, location }
485484
```
486485

487486
Running this in the REPL with bad input, we only see the first error:
488487

489-
```sh
488+
```
490489
> decodeUser =<< jsonParser "{}"
491490
Left "Expected field \"name\""
492491
```
@@ -522,7 +521,7 @@ decodeUser json = do
522521

523522
This decoder will now print all errors:
524523

525-
```purs
524+
```
526525
> import Data.Bifunctor (lmap)
527526
> decodeUser =<< lmap pure (jsonParser "{}")
528527
Left

0 commit comments

Comments
 (0)