this repo has no description
1opam-version: "2.0"
2synopsis: "Elm-inspired decoders for Ocaml"
3description: """
4A combinator library for "decoding" JSON-like values into your own Ocaml types, inspired by Elm's `Json.Decode` and `Json.Encode`.
5
6> Eh?
7
8An Ocaml program having a JSON (or YAML) data source usually goes something like this:
9
101. Get your data from somewhere. Now you have a `string`.
112. *Parse* the `string` as JSON (or YAML). Now you have a `Yojson.Basic.json`, or maybe an `Ezjsonm.value`, or perhaps a `Ocaml.yaml`.
123. *Decode* the JSON value to an Ocaml type that's actually useful for your program's domain.
13
14This library helps with step 3.
15
16## Getting started
17
18Install one of the supported decoder backends:
19
20```
21opam install decoders-ezjsonm # For Ezjsonm
22opam install decoders-ocyaml # For Ocyaml
23opam install decoders-yojson # For Yojson
24npm install --save-dev bs-decoders # For Bucklescript
25```
26
27Now we can start decoding stuff!
28
29First, a module alias to save some keystrokes. In this guide, we'll parse JSON
30using `Yojson`'s `Basic` variant.
31
32```ocaml
33utop # module D = Decoders_yojson.Basic.Decode;;
34module D = Decoders_yojson.Basic.Decode
35```
36
37Let's set our sights high and decode an integer.
38
39```ocaml
40utop # D.decode_value D.int (`Int 1);;
41- : (int, error) result = Ok 1
42```
43
44Nice! We used `decode_value`, which takes a `decoder` and a `value` (in this
45case a `Yojson.Basic.json`) and... decodes the value.
46
47```ocaml
48utop # D.decode_value;;
49- : 'a decoder -> value -> ('a, error) result = <fun>
50```
51
52For convenience we also have `decode_string`, which takes a `string` and calls
53`Yojson`'s parser under the hood.
54
55```ocaml
56utop # D.decode_string D.int "1";;
57- : (int, error) result = Ok 1
58```
59
60What about a `list` of `int`s? Here's where the "combinator" part comes in.
61
62```ocaml
63utop # D.decode_string D.(list int) "[1,2,3]";;
64- : (int list, error) result = Ok [1; 2; 3]
65```
66
67Success!
68
69Ok, so what if we get some unexpected JSON?
70
71```ocaml
72utop # #install_printer D.pp_error;;
73utop # D.decode_string D.(list int) "[1,2,true]";;
74- : (int list, error) result =
75Error while decoding a list: element 2: Expected an int, but got true
76```
77
78## Generic decoders
79
80
81Suppose our program deals with users and roles. We want to decode our JSON input
82into these types.
83
84```ocaml
85type role = Admin | User
86
87type user =
88 { name : string
89 ; roles : role list
90 }
91```
92
93Let's define our decoders. We'll write a module functor so we can re-use the
94same decoders across different JSON libraries, with YAML input, or with
95Bucklescript.
96
97```ocaml
98module My_decoders(D : Decoders.Decode.S) = struct
99 open D
100
101 let role : role decoder =
102 string >>= function
103 | "ADMIN" -> succeed Admin
104 | "USER" -> succeed User
105 | _ -> fail "Expected a role"
106
107 let user : user decoder =
108 field "name" string >>= fun name ->
109 field "roles" (list role) >>= fun roles ->
110 succeed { name; roles }
111end
112
113module My_yojson_decoders = My_decoders(Decoders_yojson.Basic.Decode)
114```
115
116Great! Let's try them out.
117
118```ocaml
119utop # open My_yojson_decoders;;
120utop # D.decode_string role {| "USER" |};;
121- : (role, error) result = Ok User
122
123utop # D.decode_string D.(field "users" (list user))
124 {| {"users": [{"name": "Alice", "roles": ["ADMIN", "USER"]},
125 {"name": "Bob", "roles": ["USER"]}]}
126 |};;
127- : (user list, error) result =
128Ok [{name = "Alice"; roles = [Admin; User]}; {name = "Bob"; roles = [User]}]
129```
130
131Let's introduce an error in the JSON:
132
133```ocaml
134utop # D.decode_string D.(field "users" (list user))
135 {| {"users": [{"name": "Alice", "roles": ["ADMIN", "USER"]},
136 {"name": "Bob", "roles": ["SUPER_USER"]}]}
137 |};;
138- : (user list, error) result =
139Error
140 in field "users":
141 while decoding a list:
142 element 1:
143 in field "roles":
144 while decoding a list:
145 element 0: Expected a role, but got "SUPER_USER"
146```
147
148We get a nice pointer that we forgot to handle the `SUPER_USER` role.
149
150## Release
151
152After updating CHANGES.md:
153
154```
155npm version <newversion>
156dune-release tag
157dune-release -p decoders,decoders-ezjsonm,decoders-yojson
158```"""
159maintainer: "Matt Bray <matt@aestheticintegration.com>"
160authors: "Matt Bray <matt@aestheticintegration.com>"
161license: "ISC"
162homepage: "https://github.com/mattjbray/ocaml-decoders"
163doc: "https://mattjbray.github.io/ocaml-decoders/decoders"
164bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues"
165depends: [
166 "ocaml"
167 "jbuilder" {>= "1.0+beta9"}
168 "cppo" {build}
169 "containers" {>= "2.8"}
170]
171build: ["jbuilder" "build" "-p" name "-j" jobs]
172conflicts: [ "dune" {>="1.7.0"} ]
173dev-repo: "git+ssh://git@github.com/mattjbray/ocaml-decoders.git"
174url {
175 src:
176 "https://github.com/mattjbray/ocaml-decoders/releases/download/0.1.0/decoders-0.1.0.tbz"
177 checksum: [
178 "sha256=291e46eab27e1c7d14b9dca366e37a0b54817ab1801dd60a565e7270fd3abb0a"
179 "md5=a97f370f3f7ff68d085ac01e05fab493"
180 ]
181}