(text json-codec)

Reference

Overview

Records to JSON and back: two traits, and a macro that writes their instances for a record.

(import (text json))
(import (text json-codec))

(def/json-type
  (: Package (Record (: name string)
                     (: version string #:default "0.1.0")
                     (: homepage (Option string) #:optional)
                     (: dependencies (Vec string) #:json "deps" #:default []))))

(match (parse-json "{\"name\": \"http\", \"deps\": [\"net\"]}")
  ((Ok j) (json->Package j))   ; (Ok (Package (name "http") (version "0.1.0") ...))
  ((Err why) (Err why)))

->json turns a value into a Json tree, and json-> reads one back, answering (Err why) when the tree is not the shape the type wants. Instances come with the module for Json itself, long, int, double, bool, string, and for (Option %a), (Vec %a) and (Map string %a) of anything that has one. A record gets its pair from def/json-type; any other type can have them written by hand.

Null is None. An Option is null when it is None, and the value itself when it is Some; nothing else reads or writes null.

Numbers. An integer type reads only a JSON integer: 1.0 is refused for an int field. A double reads either.

Errors. An error names where it happened, as far as one level down: Point.x: expected an integer, or Point: the object has no "y" field. A path through several levels of records is not given. A key in a Map prefixes its value’s error.

Not here yet. (text json) has no writer, so an encoded Json cannot yet be written out as text.

See also: def/json-type, ->json, json->

Reference

Functions

Macros

Functions

->json

function

(: ->json (-> %a Json))

A value as a Json tree.

x
The value.
returns
Its tree: a record is an object, an Option is null or its value, a Vec an array, a Map an object.

A trait. Its instances are those listed in the module’s doc, and the ones def/json-type writes for a record. An int is written as a JsonInt, a double as a JsonFloat.

See also: json->, def/json-type

json->

function

(: json-> (-> Json (Result string %a)))

A Json tree read as a value of a type.

j
The tree.
returns
The value, or why the tree is not that type's shape.

A trait. Which instance a call means is decided by the type it is used at; where nothing says, write the type’s own reader instead, such as the json->Package that def/json-type declares. An int is read only from a JsonInt that fits in one; a larger number is refused rather than wrapped.

See also: ->json, def/json-type

json-object

function

(: json-object (-> string Json (Result string (Map string Json))))
(json-object owner j)

The fields of a tree that has to be an object. Called by the code def/json-type writes.

owner
The type being read, for the message.
j
The tree.
returns
The object's fields, or Owner: expected an object.

Exported because the code def/json-type writes runs in the module that uses it, and calls this by name. Not an API for people.

See also: json-field

json-field

function

(: json-field (-> string (Map string Json) string (Result string %a)))
(json-field owner m key)

A required field of an object, read as its type. Called by the code def/json-type writes.

owner
The type being read, for the message.
m
The object's fields.
key
The field's key.
returns
The value, or why not: a missing key, or the value's own error with Owner.key: in front.

Exported because generated code calls it by name. Not an API for people.

See also: json-field/default, json-object

json-field/default

function

(: json-field/default (-> string (Map string Json) string %a (Result string %a)))
(json-field/default owner m key fallback)

A field that may be absent, read as its type. Called by the code def/json-type writes.

owner
The type being read, for the message.
m
The object's fields.
key
The field's key.
fallback
What an absent field, or one that is null, is read as.
returns
The value, the fallback, or the value's own error with Owner.key: in front.

Exported because generated code calls it by name. Not an API for people.

See also: json-field

Macros

def/json-type

macro

(def/json-type declaration)

Declares a record, and the instances that write it as JSON and read it back.

declaration
A record declaration, as type takes one, whose fields may carry the markers below.
(def/json-type
  (: (Page %a) (Record (: items (Vec %a))
                       (: next (Option string) #:optional)
                       (: total int #:json "totalCount"))))

(json->Page j)          ; (Result string (Page %a)), given (json-> %a)
(Page->json page)       ; Json

(def/json-type (: Name (Record (: field type marker ...) ...))) declares the record Name as type would, then an ->json and a json-> instance for it, and two functions that name the type: Name->json and json->Name. A type with parameters, (: (Page %a) ...), gets instances that need the same trait of each parameter.

A record is an object with a key for each field. The markers, after a field’s type:

A field without #:default or #:optional is required, and reading an object without it is an error. Keys the record has no field for are passed over.

The field types are not looked at: what a field is written as is settled by the instance its type has, so a field of a type with no ->json is an error where the instance is wanted, not here.

See also: ->json, json->