json-type-provider
json-type-provider copied to clipboard
Well-typed JSON parser generator inspired by Type Provider
json-type-provider
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
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
Installation
raco pkg install json-type-provider
Documentation
(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 type
The 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))