# json-schema

Author Matt Novenstern 1.0.2 LGPL https://fisxoj.github.io/json-schema/

json-schema is a validator for drafts 4, 6, 7, and 2019-09 of the JSON Schema standard. It is (mostly) compliant with the common test suite. The exceptions are

Draft 2019-09:

• unevaluatedItems and unevaluatedProperties are unimplemented

Drafts 4, 6, 7:

## Usage Notes

### Contexts

A context is a reusable set of state that contains all of the fetched network resources (if your schema references external resources) and resolved ids. By storing that all, you can reuse the validation context multiple times without fetching/resolving everything again.

(ql:quickload '(trivial-benchmark json-schema))

;; schema is the json-schema meta schema document from:

(defvar *context*
(json-schema:make-context
*schema*
:draft2019-09))

;;; Cached

(let ((data (json-schema.parse:parse "{\"type\": \"string\"}")))
(trivial-benchmark:with-timing (1000)
(json-schema:validate data
:context *context*)))

;; -                SAMPLES  TOTAL      MINIMUM  MAXIMUM   MEDIAN    AVERAGE    DEVIATION
;; REAL-TIME        1000     0.826      0        0.022     0.001     0.000826   0.000797
;; RUN-TIME         1000     0.826      0        0.022     0.001     0.000826   0.0008
;; USER-RUN-TIME    1000     0.781011   0        0.020644  0.000745  0.000781   0.000665
;; SYSTEM-RUN-TIME  1000     0.049933   0        0.000986  0         0.00005    0.000184
;; PAGE-FAULTS      1000     0          0        0         0         0          0.0
;; GC-RUN-TIME      1000     0.02       0        0.02      0         0.00002    0.000632
;; BYTES-CONSED     1000     213753664  195344   228976    228032    213753.66  16221.591
;; EVAL-CALLS       1000     0          0        0         0         0          0.0

;;; Uncached

(let ((data (json-schema.parse:parse "{\"type\": \"string\"}")))
(trivial-benchmark:with-timing (1000)
(json-schema:validate data
:schema *schema*
:schema-version :draft2019-09)))

;; -                SAMPLES  TOTAL      MINIMUM   MAXIMUM   MEDIAN    AVERAGE   DEVIATION
;; REAL-TIME        1000     203.185    0.148     1.471     0.185     0.203185  0.112807
;; RUN-TIME         1000     9.25       0.006     0.04      0.009     0.00925   0.002294
;; USER-RUN-TIME    1000     8.145081   0.003368  0.039067  0.008105  0.008145  0.002317
;; SYSTEM-RUN-TIME  1000     1.107377   0         0.004927  0.000994  0.001107  0.000967
;; PAGE-FAULTS      1000     0          0         0         0         0         0.0
;; GC-RUN-TIME      1000     0.08       0         0.03      0         0.00008   0.001464
;; BYTES-CONSED     1000     719780512  707728    751424    718160    719780.5  11026.181
;; EVAL-CALLS       1000     0          0         0         0         0         0.0



Thank you to Raymond Wiker for contributing the initial implementation.

### Decoding JSON

json-schema operates mostly on common-lisp:hash-table objects. It requires them to have the :test argument set to common-lisp:equal, so that they work with string keys. Further, it expects :true and :false as the boolean values and :null as the decoded Javascript null. Javascrpit arrays should be rendered as lists. This behavior is provided behind the scenes by st-json. The json-schema.parse:parse function provides this functionality over strings, streams, and pathnames for you.

### Network access

JSON Schema allows schemas to reference other documents over the network. This library will fetch them automatically, by default. If you don't want this to be allowed, you should set json-schema.reference:*resolve-remote-references* to nil. If a schema references a remote one, it will raise a json-schema.reference:fetching-not-allowed-error instead of fetching it when fetching references is disallowed.

### Reusing Schemas

Because of the nature of JSON Schema's references (location-independent references, particularly), schema documents need to be walked when loaded to discover named anchors and ids. They also may load other schemas.

If you're reusing a large schema document repeatedly, you might want to cache the resolution context. Unfortunately, I'm still working on this feature!