hjsonschema logo

A Haskell implementation of JSON Schema (Draft 4).

Hackage / GitHub / Travis CI


  • As of 2017 json-schema-org has begun releasing new drafts of the standard. Once this work stabilizes hjsonschema will add coverage for the latest draft.

  • Requires pcre (pkgs.pcre in Nixpkgs).

  • Schemas with circular references can cause infinite loops. hjsonschema does loop detection but it may not be solid yet – please open an issue if you find a situation where it fails.


See here.


Run all tests:

stack test

Run only local tests:

stack test hjsonschema:local

Run remote tests (makes GETs to json-schema.org, also temporarily starts an HTTP server on port 1234):

stack test hjsonschema:remote



  • Be a correct and fast implementation of the spec.

  • Be a useful reference for implementers in other languages. Haskell’s high level nature, expressive type system and referential transparency suit this purpose well.


  • Doesn’t pass all of the tests in the language agnostic test suite. See the issue list for details.

  • Uses the pcre-heavy regular expression library for the “pattern” validator. It should use a library based on the ECMA 262 regex dialect, which the spec requires.

  • Currently doesn’t support the optional "format" validators.


  • JSON-Schema-Test-Suite is vendored from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 here.

  • src/draft4.json is from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 here. The root ref in remote ref test has been modified to fix #175.

  • .travis.yml was created with make_travis_yml_2.hs commit # ea6c7d177a97bfbfb2fdc4deba943d60d2aff199.


TJ Weigel created the logo.

Tim Baumann wrote aeson-schema, on which hjsonschema’s test code and its implementation of SchemaGraph were based.

Julian Berman maintains the fantastic language agnostic test suite.



  • Remove upper bounds.


  • Bump http-types.


  • Test with GHC 8.2. Drop GHC 7.8.
  • Rework allUniqueValues related utility functions.


  • Bump hjsonpointer and QuickCheck.


  • Bump aeson.


  • Fix Haddocks.


  • Fix defect where validators alongside “$ref” weren’t ignored.

  • Fix defect where local references would fail if an “id” key had set resolution scope to start from a different document.

  • Vendor latest tests.

  • Remove ReferencedSchemas.

  • Create Scope to hold information that changes during validation.

  • Use a sum type for “type” values. Thanks to Philip Weaver (GitHub @pheaver).

  • Raise test dep upper bounds.

  • Report details of "required" validator failure.
  • Bump directory.

  • Rename Data.JsonSchema.* modules to JSONSchema.*.
  • Rename Data.Validator.* modules to JSONSchema.Validator.*.

  • Bump vector.

  • Rewrite failure messages.

We used to return a list of every failed validator, no matter how far it was buried within subschemas of the original schema.

Now we return a tree of failure messages, so that if the first schema had only three validators, then no more than three top level failures will be returned.

  • Move the code to parse each validator from JSON from Data.Validator.Draft4 into the validators’ modules themselves.

  • Switch from Prelude to Protolude.

  • Switch Data.JsonSchema.Fetch from lazy to strict bytestrings.

  • Bump hspec.

  • Switch to hspec for tests.

  • Return AdditionalPropertiesObject error correctly (was mistakenly returning AdditionalItemsObject instead.
  • Don’t silence errors resulting from subschemas of “anyOf” or “oneOf”.

  • Bump aeson and hjsonpointer.

  • Rename schemaForSchemas to metaSchema and schemaForSchemasBytes to metaSchemaBytes.

Bug fixes:

  • Fix JSON Pointer bug. Pointers were being built in reverse order and so were totally invalid.
  • Use .:! instead of .:? to parse the draft 4 schema. The only way to omit optional fields in JSON Schema Draft 4 is to omit them entirely, "null" can’t be used for this.

API Changes:

  • Add referenced schema loop detection.
  • Add a new referencesValidity function.
  • checkSchema now checks referenced schema’s validity in addition to the starting schema’s validity. This change bubbles up to the one-step validation functions as well.
  • Switch most of the fetching code to use URISchemaMap instead of ReferencedSchemas. It didn’t need to know about the more complicated data type.
  • Rething failure related names. Change Invalid to Failure, add a new Invalid type alias which is only used for final results.
  • Failures now include the failing part of the data as well as a JSON Pointer to it, so you don’t have to worry about resolving the pointer.

Fundamental Changes:

  • Make Fail (previously Failure) an instance of Functor.
  • Add a Validator data type which is an instance of Profunctor.
  • Add a Spec data type for collections of Validators.


  • Switch from 2 to 4 space indentation.
  • Update the vendored JSON Schema Test Suite.

  • Bump http-client.

  • Enable GHC 8.

  • Fix .cabal file.


  • Rewrite fetching internals.
  • Fix reference resolution defects, add more tests.
  • Switch to a Perl style regex library, which is closer to ECMAScript regexes than the previous Posix style one.
  • Add one-step validation functions (‘fetchFilesystemAndValidate’ and ‘fetchHTTPAndValidate’).
  • Alias the validation failure type exported by ‘Data.JsonSchema.Draft4’ to ‘Invalid’, change its field names.


  • Partial rewrite. The API of the library has changed, see the examples folder for how to use the new one.

  • Users of the library can now write schemas in Haskell as well as JSON.


  • Improve scope updating and resolving.
  • Rename RawSchema’s _rsObject field to _rsData.
  • Make RawSchema’s _rsURI field a Maybe. This way schemas without a starting URI can say so explicitly with Nothing instead of with “”.
  • Rename Graph to SchemaGraph. Declare it with data instead of type. Give it a field referencing the starting schema. This field is used to find the curent schema if no URI is in scope and a self-referencing $ref is found (e.g. “#”).
  • Change the order of the last two arguments to fetchReferencedSchemas.


  • Support GHC 7.8 again.


Change error type from Text to ValidationFailure.

Revert the 0.6 changes to validate. Also switch from Vector to list. Validate is now: Schema err -> Value -> [ValidationFailure err]

Add fetchReferencedSchemas’, which lets the user provide their own MonadIO function to be used when fetching schemas. This lets them do things like only fetch schemas from particular domains.


Break the API so the library doesn’t induce boolean blindness.

Change validate was: Schema -> Value -> Vector ValErr now: Schema -> Value -> Either (Vector ValErr) Value

Change Schema was: type Schema = Vector Validator now: newtype Schema = Schema { _unSchema :: [Validator] }


  • Switch from http-conduit to http-client.


  • Add convenience function for validating and compiling draft 4 schemas simultaneously.


  • Switch from wreq to http-conduit; drop lens dependency.


  • Start changelog.
  • Rename Utils.hs to Helpers.hs.
  • Move all non-ValidatorGen functions in Validators.hs to Helpers.hs.
  • Various touchups.