GithubHelp home page GithubHelp logo

jijo's Introduction

jijo: Bidirectional JSON serialization

Build Status

Design Goals

  • Explicitness – decouple types and encoders/decoders (unlike autoderived instances in Aeson).

  • Bidirectionality – use the same definition for encoding and decoding to prevent mistakes when one side of the definition is updated and the other is not.

  • Completeness – collect as many validation errors as possible, instead of stopping after the first error.

Module Structure

Core:

  • JSON.Definition – the core of the framework, includes combinators for defining complete JSON definitions, parsing primitives, objects, sums, and adding predicates to validate complex conditions.

  • JSON.Validation – the validation machinery, complex enough to deserve its own module.

  • JSON.Path – utilities for working with JSONPath, which is used for error reporting.

Records:

  • RecordField.* – helpers for generating record constructors that make it harder to mix up fields when decoding records from JSON.

An Example

$ stack repl

Encoding:

> uuid <- Data.UUID.V4.nextRandom

> encodeViaDefinition jUUID uuid
String "c7d63bec-517b-48d8-b77a-bc44d05f24af"

Decoding, happy path:

> import Data.Aeson

> validateViaDefinition jUUID (String "c7d63bec-517b-48d8-b77a-bc44d05f24af")
Right c7d63bec-517b-48d8-b77a-bc44d05f24af

Decoding, type mismatch:

> validateViaDefinition jUUID (Number 42)
Left (JValidationReport [JTypeNotOneOf (fromList [JTyString])] (fromList []))

Decoding, malformed UUID:

> validateViaDefinition jUUID (String "invalid")
Left (JValidationReport [JValidationFail InvalidUUID] (fromList []))

The errors are returned as a prefix tree of JValidationErrors indexed by JPathSegment. They can include domain-specific errors.

Implementation Details

JValidation

JValidation is defined as follows:

data JValidation e a =
  JValidation (Maybe a) (JValidationReport e)

data JValidationReport e =
  JValidationReport [JValidationError e] (Map JPathSegment (JValidationReport e))
  • e is the type of domain-specific errors.
  • j is the validation input (for example, JSON.Value)
  • a is the validation result.

The Applicative instance for JValidation accumulates errors from all subcomputations. We don't want to have a Monad instance for JValidation because it would violate the (<*>) = ap law.

JDefinition

JDefinition is a categorical (arrow) product of a validator and an encoder:

type JDefinition e = ArrPair (ValidationArr e) EncodingArr

data ArrPair p q j a = ArrPair (p j a) (q j a)

newtype ValidationArr e j a =
  ValidationArr (j -> JValidation e a)

newtype EncodingArr j a =
  EncodingArr (a -> j)

It has a Category instance that can be used for sequential/monadic validation: any failed step of the pipeline aborts the pipeline. In most cases, a JDefinition can be built by using the same recipe:

  • narrow down the type using one of existing primitive combinators
  • (jString, jObject, etc), parse (probably using jObjectDefinition),
  • then add extra predicates using jDefinition.

JObjectDefinition

JObjectDefinition is an applicative Product of a validator and an encoder. It can be converted into a JDefinition. It does not have a Monad instance but it can be used for "parallel" applicative validation – all errors will be reported in parallel.

makeRecBuilder

jField uses explicit type applications so that fields would not be mixed up; makeRecBuilder wraps constructors into something that takes explicitly named fields.

Future Work

  • Use -XDerivingVia instead of coerce once GHC 8.10 is out (due to three-release policy).

  • Better document how to use sum type validation. There are tests in JSON.DefinitionSpec but no docs yet.

  • TODO: comment on BadExponent.

  • Move the Field machinery into named?

  • Use something like Barbies or higgledy to get rid of Field and move field names into types?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.