This is a library for parsing JSON input into Typed Racket values. By specifying the JSON schema in Typed Racket, the programmer gets a well-typed parser.
Nice things the library provides:
- No error-handling boilerplate.
- Flexibility in mapping from JSON format into Racket types. For example, by default, objects are parsed into compact structs that only store fields the programmer cares about. It is also possible to specify a custom conversion that say, convert an object with
realandimagdirectly into Racket'sComplex.
Examples are under test/ directory
- london_weather.rkt shows a straightforward declaration
- complex.rkt shows how to convert objects or lists into custom types
- cards.rkt shows how to impose a more precise type (e.g. enumerations) on raw data
raco pkg install json-type-provider
(There will eventually be Scriblings)
The define-json-types macro will define a type id and generate a parser read-id
for each declared id type, whose RHS describes the shape of the data
and optionally how it is mapped into a custom Racket type.
(require json-comb)
(define-json-types
[id desc] ...)Below is the full grammar:
desc ::= obj-desc | type-desc
type-desc ::= simp-type-desc | (U simp-type-desc ...)
simp-type-desc ::= JSNum
| Real
| Integer
| Float
| Boolean
| String
| #t
| #f
| 'null
| id
| list-type-desc
| (pat => type #:by expr)
| ((Listof type-desc) => type #:by-folding expr #:from expr)
list-type-desc ::= (List type-desc ...)
| (Listof type-desc)
| (List* type-desc ... (Listof type-desc))
pat ::= (List [id : type-desc] ...)
| (List* [id : type-desc] ... [id : (Listof type-desc)])
| obj-desc
| [x : type-desc]
obj-desc ::= (field-desc ... rest-option)
rest-option ::=
| #:ignore-others
| #:log-warning-others
| #:error-others
field-desc ::= [field-name : type-desc]
| [field-name : type-desc #:default [expr : type]]
field-name ::= id
| (id id)
type = arbitrary Racket typeThe libary also provides convenient functions over JSON lists:
;; Parse and fold a JSON list of `X`s into `A` without building an intermediate list
read-fold : (∀ (X A) A (X A → A) (Input-Port → X) → (∀ (B)
(case->
[Input-Port → A]
[Input-Port (Input-Port → B) → (U A B)])))
;; Create a sequence of `X` without building an intermediate list
make-sequence-reader : (∀ (X) (Input-Port → X) → Input-Port → (Sequenceof X))