Define
Create a named validation with an id and a schema. That id is what apps use when they validate future entities.
Validations let an account describe the shape an entity should have and run that check when data arrives.
Use them when your application needs flexible entities now, with stronger rules added over time.
Create a named validation with an id and a schema. That id is what apps use when they validate future entities.
Update the same validation id when the schema changes. Each schema version remains available and can have a friendly version alias.
Run a validation to get errors without storing anything, or use persist-if-valid to validate first and save only when the entity passes.
Malli is a data-driven schema library for Clojure. Ship Deploy stores Malli schemas as JSON, which lets applications define, version, and use validation rules through the API without embedding Clojure code.
Most schemas use vector syntax shaped like [type, optional-properties, child-schemas...]. Read them from the outside in: the first item names the rule, an optional object configures it, and the remaining items describe fields or nested values.
[
"map",
{"closed": true},
["name", "non-blank-string"],
["email", {"optional": true}, "email-address"],
["roles", ["vector", ["enum", "admin", "member"]]],
["age", ["and", "int", [">=", 18]]]
]map expects an object. Each child names a field and its schema. Fields are required unless they include {"optional": true}. Maps accept extra fields by default; add {"closed": true} to reject them.
vector applies one child schema to every array item. enum limits a value to listed choices. Use map, vector, tuple, or map-of inside one another for nested data.
and requires every child rule to pass, while or accepts any child rule. maybe accepts either nil or its child schema. Comparators such as >= 18 add numeric constraints.
Malli documentation uses Clojure keywords such as :map and :string. In Ship Deploy JSON requests, send "map" and "string". Account primitives such as non-blank-string extend Malli's built-in forms.
Each definition has a validation-id, a display name, and a schema. A version can also have a version-alias such as stable or compatible. The schema can use built-in primitives like non-blank-string and email-address, plus normal Malli forms for maps, numbers, booleans, enums, and nested data.
Returns built-in validation ids you can compose into account schemas.
Checks a single value against one primitive validator.
Creates a new schema version for an account validation id, with an optional friendly version alias.
Lists the version history for a validation id so changes can be inspected later.
Define a schema once and refer to it by validation-id from application code. The optional version-alias gives this specific version a stable friendly name.
curl -X POST https://shipdeploy.work/api/v1/validations.json \
-H 'content-type: application/json' \
-H 'x-api-key: replace-with-your-api-key' \
-d '{"validation-id":"person","version-alias":"compatible","name":"Person","schema":["map",["first-name","non-blank-string"],["last-name","non-blank-string"],["email","email-address"]]}'When your model changes, update the same validation id. The new schema becomes current, and the previous schema is kept in the version history.
curl -X PUT https://shipdeploy.work/api/v1/validations/person.json \
-H 'content-type: application/json' \
-H 'x-api-key: replace-with-your-api-key' \
-d '{"version-alias":"strict","name":"Person","schema":["map",["first-name","non-blank-string"],["last-name","non-blank-string"],["email","email-address"],["department",["enum","research","operations","sales"]]]}'curl https://shipdeploy.work/api/v1/validations/person/versions.json \
-H 'x-api-key: replace-with-your-api-key'Use this when a form, workflow, or import job needs a validation result before deciding what to do next. Omit version selectors for the latest schema, or provide either version or version-alias for a specific version.
curl -X POST https://shipdeploy.work/api/v1/validations/validate.json \
-H 'content-type: application/json' \
-H 'x-api-key: replace-with-your-api-key' \
-d '{"validation-id":"person","version-alias":"compatible","value":{"first-name":"Ada","last-name":"Lovelace","email":"ada@example.com"}}'Use persist-if-valid when the schema describes the whole entity envelope. Invalid entities return 422 with validation errors and are not stored.
curl -X POST https://shipdeploy.work/api/v1/validations.json \
-H 'content-type: application/json' \
-H 'x-api-key: replace-with-your-api-key' \
-d '{"validation-id":"person-entity","version-alias":"stable","name":"Person entity","schema":["map",["id","non-blank-string"],["type",["=","person"]],["data",["map",["first-name","non-blank-string"],["last-name","non-blank-string"],["email","email-address"]]]]}'curl -X POST https://shipdeploy.work/api/v1/entities/persist-if-valid.json \
-H 'content-type: application/json' \
-H 'x-api-key: replace-with-your-api-key' \
-d '{"validation-id":"person-entity","version-alias":"stable","entity":{"id":"person-ada","type":"person","data":{"first-name":"Ada","last-name":"Lovelace","email":"ada@example.com"}}}'Applications normally start with loose entity storage, then add validations for the entity types that have become important. Over time, each validation id carries its own version history.
List current active definitions for the account.
Fetch the current schema for one validation id.
Retire a validation when it should no longer be listed or used by new writes.