An open API service indexing awesome lists of open source software.

https://github.com/mmontone/schemata

Schema serialization, validation and parsing for Common Lisp.
https://github.com/mmontone/schemata

common-lisp json-schema lisp schema serialization validation

Last synced: about 1 month ago
JSON representation

Schema serialization, validation and parsing for Common Lisp.

Awesome Lists containing this project

README

        

# SCHEMATA

Generic purpose schema library for serialization and validation of data.

This library is used by CL-REST-SERVER for API serialization and validation.

It features:
- Validation using schemas.
- Serialization and unserialization using schemas.
- Generation of (random) data from schemas. (incomplete implementation atm)
- JSON-Schema parsing (incomplete implementation atm)
- Itegration with Common Lisp type system.
- A schema class metaclass.

## Example

```lisp
(schemata:defschema customer
(object "customer"
((id string :external-name "id" :accessor
customer-id :documentation "customer id")
(number string :external-name "number" :required nil
:accessor customer-nr :documentation
"customer number")
(name string :external-name "name" :accessor
customer-name :documentation "customer name")
(address-1 string :external-name "address1"
:required nil :documentation
"customer first address")
(address-2 string :external-name "address2"
:required nil :documentation
"customer second address")
(postal-code string :external-name "postalcode"
:required nil :documentation
"postal code")
(postal-area string :external-name "postalarea"
:required nil :documentation
"postal area")
(country string :external-name "country" :required nil
:documentation "country code")
(phone string :external-name "phone" :required nil
:documentation "phone")
(fax string :external-name "fax" :required nil
:documentation "fax")
(email string :external-name "email" :required nil
:documentation "email"))
(:documentation "customer data fetched")))
```

[Read the full documentation](https://mmontone.github.io/schemata/ "Full documentation")

## Schema types

### Type schemas

Schemas can be built from Common Lisp types:

```lisp
SCHEMATA> (defparameter *s* (schema string))
*S*
SCHEMATA> *s*
#
SCHEMATA> (validate-with-schema *s* "22")
NIL
SCHEMATA> (validate-with-schema *s* 22 :error-p nil)
#
```

### Object schema

Object schemas are built using the syntax: `(object name attributes options)`.
Attributes are specified as: `(attribute-name attribute-type &rest options)`.

The `attribute-type` is parsed as a schema.

Possible attribute options are: `required`, `required-message`, `default`, `accessor`, `writer`, `reader`, `parser`, `validator`, `add-validator`, `formatter`, `external-name`, `serializer`, `unserializer`, `slot`.

Example:

```lisp
SCHEMATA> (schema (object person
((name string)
(age integer :required nil))))
#
```

### List schema

Homogeneous list of schemas are specified via `list-of`.

Example:

```lisp
SCHEMATA> (defparameter *s* (schema (list-of integer)))
*S*
SCHEMATA> (validate-with-schema *s* '(1 2 "foo"))
; Evaluation aborted on #.
SCHEMATA> (validate-with-schema *s* '(1 2 3))
NIL
```
### Schema references

Defined schemas can be referenced via either `(schema schema-name)` or `(ref schema-name)` (they are identical).

Example:

```lisp
SCHEMATA> (defschema person
(object person
((name string))))
#
SCHEMATA> (defparameter *list-of-person* (schema (list-of (ref person))))
*LIST-OF-PERSON*
SCHEMATA> *list-of-person*
#
SCHEMATA> (parse-with-schema *list-of-person* '((("name" . "Mariano")) (("name" . "Peter"))))
(((NAME . "Mariano")) ((NAME . "Peter")))
SCHEMATA> (validate-with-schema *list-of-person* '((("name" . 22)) (("name" . "Peter"))))
; processing (DEFMETHOD SCHEMA-VALIDATE ...); Evaluation aborted on #.
SCHEMATA> (validate-with-schema *list-of-person* '((("name" . 22)) (("name" . "Peter"))))
; Evaluation aborted on #.
SCHEMATA> (validate-with-schema *list-of-person* '((("name" . "Mariano")) (("name" . "Peter"))))
NIL
SCHEMATA> (validate-with-schema *list-of-person* '((("names" . "Mariano")) (("name" . "Peter"))))
; Evaluation aborted on #.
```

## SATISFIES-SCHEMA type

Schemata integrates with the Lisp type system via the SATISFIES-SCHEMA type.
Schemas can be thought as types over data.
Defined schemas can be checked using TYPEP and CHECK-TYPE with the type `(satisfies-schema schema-name)`.

Example:

```lisp
SCHEMATA> (defschema string-schema string)
#
SCHEMATA> (typep "foo" '(satisfies-schema string-schema))
T
SCHEMATA> (typep 22 '(satisfies-schema string-schema))
NIL
SCHEMATA> (let ((x "foo"))
(check-type x (satisfies-schema string-schema))
x)
"foo"
```

## SCHEMA-CLASS metaclass

SCHEMA-CLASS classes get an schema attached.

Example:

```lisp
SCHEMATA> (def-schema-class person ()
((name :type string :initarg :name)
(age :type integer :required nil :initarg :age)))
#

SCHEMATA> (validate-with-schema (find-class 'person) '(("name" . "Mariano") ("age" . 22)))
NIL

SCHEMATA> (validate-with-schema (find-class 'person) '(("name" . "Mariano") ("age" . 'asdf)) :error-p nil)
#

SCHEMATA> (generic-serializer:with-serializer :json
(generic-serializer:serialize (make-instance 'person :name "Mariano" :age 44)))
{"name":"Mariano","age":44}
```

## More schema types

[Read more](https://mmontone.github.io/schemata/#Schema-types) about other schema types, like association-lists, property-lists, hash-tables, etc.