on json-schema-export help sign in

type-safe JSON spec and validation tool

git clone ssh://git.iko.soy/schematic

schematic

Build Status

Goal

The goal of the library is to provide a type-safe transport layer for serializing and validating JSON. It can be thought of as a subset of json-schema, which is basically a specification of a JSON document. The other goal is getting as much as possible from this specification for free. Right now the following bits are prototyped:

TODO

Be aware that library is experimental and subject to change a lot. The current state can be viewed as a prototype.

Installation

$ stack install schematic

Basic Examples

type SchemaExample
  = SchemaObject
    '[ '("foo", SchemaArray '[AEq 1] (SchemaNumber '[NGt 10]))
     , '("bar", SchemaOptional (SchemaText '[TEnum '["foo", "bar"]]))]

This one is valid for example

schemaJson :: ByteString
schemaJson = "{\"foo\": [13], \"bar\": null}"

Also valid

schemaJson :: ByteString
schemaJson = "{\"foo\": [13], \"bar\": \"bar\"}"

it can be parsed and validated like this:

decodeAndValidateJson schemaJson :: ParseResult (JsonRepr SchemaExample)

ParseResult type encodes three possible situations:

It implies a transport layer representation of that data that can be traversed and transformed to whatever internal types user has. It's called JsonRepr. Type parameter is the schema itself.

jsonExample :: JsonRepr SchemaExample
jsonExample = ReprObject $
  FieldRepr (ReprArray [ReprNumber 12])
    :& FieldRepr (ReprOptional (Just (ReprText "bar")))
    :& RNil

Migrations

It's possible to represent schema changes as a series of migrations, which describes a series of json-path/change pairs. Migrations can be applied in succession.

This piece of code will apply a migration to the schema, decode and validate the latest version.

type SchemaExample
  = SchemaObject
    '[ '("foo", SchemaArray '[AEq 1] (SchemaNumber '[NGt 10]))
     , '("bar", SchemaOptional (SchemaText '[TEnum '["foo", "bar"]]))]

type TestMigration =
  'Migration "test_revision"
    '[ 'Diff '[ 'PKey "bar" ] ('Update ('SchemaText '[]))
     , 'Diff '[ 'PKey "foo" ] ('Update ('SchemaNumber '[])) ]

type VS = 'Versioned SchemaExample '[ TestMigration ]

schemaJsonTopVersion :: ByteString
schemaJsonTopVersion = "{ \"foo\": 42, \"bar\": \"bar\" }"

It's possible to decode the latest version like this:

decodeAndValidateJson schemaJsonTopVersion :: ParseResult (JsonRepr (TopVersion (AllVersions VS)))

Lens-compatibility

It's possible to use flens to construct a field lens for a typed object in schematic. Let's suppose you have a schema like this:

type ArraySchema = 'SchemaArray '[AEq 1] ('SchemaNumber '[NGt 10])

type ArrayField = '("foo", ArraySchema)

type FieldsSchema =
  '[ ArrayField, '("bar", 'SchemaOptional ('SchemaText '[TEnum '["foo", "bar"]]))]

type SchemaExample = 'SchemaObject FieldsSchema

There are two ways of working with named fields in the objects: