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.
- Host: GitHub
- URL: https://github.com/mmontone/schemata
- Owner: mmontone
- Created: 2020-05-17T16:37:01.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2024-05-03T11:53:50.000Z (about 1 year ago)
- Last Synced: 2025-03-27T02:21:46.353Z (about 2 months ago)
- Topics: common-lisp, json-schema, lisp, schema, serialization, validation
- Language: Common Lisp
- Homepage: https://mmontone.github.io/schemata/
- Size: 1.35 MB
- Stars: 11
- Watchers: 3
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
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 referencesDefined 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)))
NILSCHEMATA> (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.