3`yoga-json` is a light-weight and simple json library for purescript.
5**Note**: This library was initially forked from the amazing [simple-json](https://github.com/justinwoo/purescript-simple-json) ([MIT Licence](./LICENSE/simple-json.LICENSE)).
6Replace your imports from `Simple.JSON` to `Yoga.JSON` to migrate.
9* [installation](#installation)
14* ๐ simple and easy to use json codecs
16* ๐ค built-in support for many common types (`Sum` types, Tuples, BigInts, Maps, JSDate, DateTime, Eithers, NonEmptyStrings )
17* ๐ human-friendly error reporting
22spago install yoga-json
27`purescript-yoga-json` basically provides two functions `writeJSON` and `readJSON`.
29Use `writeJSON` to serialise a type to a JSON string:
32import Yoga.JSON as JSON
36 JSON.writeJSON { first_name: "Lola", last_name: "Flores" }
37 -- {"last_name":"Flores","first_name":"Lola"}
40Use `readJSON` to deserialise a JSON string:
42import Yoga.JSON as JSON
44deserialised :: Either MultipleErrors { first_name :: String, last_name :: String }
45deserialised = JSON.readJSON """{ "first_name": "Lola", "last_name": "Flores" }"""
46-- Right { first_name: "Lola", last_name: "Flores" }
49As the parsing can fail, `readJSON` returns an `Either`, potentially containing a `Left` data constructor with `MultipleErrors`. If you don't care about the specific errors, you can use `readJSON_`, which returns a `Maybe`:
52deserialised :: Maybe { first_name :: String, last_name :: String }
53deserialised = JSON.readJSON_ """{ "first_name": "Lola", "last_name": "Flores" }"""
54-- Just { first_name: "Lola", last_name: "Flores" }
60`purescript-yoga-json` provides utility functions to easily generate serialisers and deserialisers for your sum types.
62Let's start with a simple example of a sum type where our data constructors do not contain any further values:
65import Data.Either (Either)
66import Data.Generic.Rep (class Generic)
67import Yoga.JSON as JSON
68import Yoga.JSON.Generics (genericReadForeignEnum, genericWriteForeignEnum)
69import Yoga.JSON.Generics.EnumSumRep as Enum
71data MyEnum = Enum1 | Enum2 | Enum3
74Now, we need to derive a `Generic` instance for it:
77derive instance Generic MyEnum _
78-- and optionally a Show instance
79instance Show MyEnum where
83Next, we define a `WriteForeign` instance and implement the `writeImpl` function using `genericWriteForeignEnum Enum.defaultOptions`.
86instance WriteForeign MyEnum
88 writeImpl = genericWriteForeignEnum Enum.defaultOptions
91Similarly, we implement the `ReadForeign` instance using `genericReadForeignEnum Enum.defaultOptions`
93instance ReadForeign MyEnum
95 readImpl = genericReadForeignEnum Enum.defaultOptions
98That's all, we can now serialise our data type:
100serialised = writeJSON { "myEnum": Enum3 }
105deserialised :: E { "myEnum" :: MyEnum }
106deserialised = readJSON serialised
107-- Right { myEnum: Enum3 }
110### Writing custom codecs
112In order to write your own, custom codecs you will need to provide instances for `WriteForeign` and `ReadForeign`.
114Let's see an example. We define a simple data type `TrafficLight` that has three data constructors `Red`, `Yellow` and `Green`:
116data TrafficLight = Red | Yellow | Green
118We would like to serialise these constructors as lower case strings `"red"`, `"yellow"` and `"green"`.
120First we need to provide an implementation for the `WriteForeign` type class, that tells `yoga-json` how to serialise the type. We pattern match on the three different data constructors and write them as the three `String`s red, yellow and green, using the same `writeImpl` function:
122instance WriteForeign TrafficLight where
123 writeImpl Red = writeImpl "red"
124 writeImpl Yellow = writeImpl "yellow"
125 writeImpl Green = writeImpl "green"
127This works, because `yoga-json` already nows how to serialise a `String`.
129Similarly, we need to provide an implementation for the `ReadForeign` type class, that tells `yoga-json` how to deserialise the type. We start by deserialising into a primitive type, typically a String or an Object, and then convert it to our desired Purescript type.
131Since we don't know the input `String`, it might contain invalid data and therefore deserialisation might fail. `yoga-json` uses the `ExceptT` monad to reflect this. We can return valid values using `pure` and `fail` on invalid values:
134instance ReadForeign TrafficLight where
136 -- deserialise into a string
137 str :: String <- readImpl json
138 -- now we pattern match on our valid types
141 "yellow" -> pure Yellow
142 "green" -> pure Green
143 -- and fail if we get an invalid type
144 other -> fail $ ForeignError $ "Failed to parse " <> other <> " as TrafficLight"
147Now we can serialise our data type:
149serialised = writeJSON { "trafficLight": Red }
150-- {"trafficLight":"red"}
155deserialised :: E { "trafficLight" :: TrafficLight }
156deserialised = readJSON """{ "trafficLight": "green" }"""
157-- Right { trafficLight: Green }
159deserialisedUnknown :: E { "trafficLight" :: TrafficLight }
160deserialisedUnknown = readJSON """{ "trafficLight": "purple" }"""
161-- Left (NonEmptyList (NonEmpty (ErrorAtProperty "trafficLight" (ForeignError "Failed to parse purple as TrafficLight")) Nil))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list