Validation docs

Define versioned validations and use them before data is stored.

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.

01

Define

Create a named validation with an id and a schema. That id is what apps use when they validate future entities.

02

Version

Update the same validation id when the schema changes. Each schema version remains available and can have a friendly version alias.

03

Use

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 schema basics

Schemas are data that describe data

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.

Malli schema in JSON
[
  "map",
  {"closed": true},
  ["name", "non-blank-string"],
  ["email", {"optional": true}, "email-address"],
  ["roles", ["vector", ["enum", "admin", "member"]]],
  ["age", ["and", "int", [">=", 18]]]
]

Objects and fields

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.

Collections and choices

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.

Combining rules

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.

JSON notation

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.

How validation definitions work

A validation is a reusable schema

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.

GET /validations/primitives

List primitive validators

Returns built-in validation ids you can compose into account schemas.

POST /validations/primitives/{primitive-id}/validate

Try one primitive

Checks a single value against one primitive validator.

POST /validations

Define a validation

Creates a new schema version for an account validation id, with an optional friendly version alias.

GET /validations/{validation-id}/versions

Review versions

Lists the version history for a validation id so changes can be inspected later.

Define a validation schema

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.

Example
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"]]}'

Create the next version

When your model changes, update the same validation id. The new schema becomes current, and the previous schema is kept in the version history.

Example
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"]]]}'
Example
curl https://shipdeploy.work/api/v1/validations/person/versions.json \
  -H 'x-api-key: replace-with-your-api-key'

Validate without storing

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.

Example
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"}}'

Persist only when valid

Use persist-if-valid when the schema describes the whole entity envelope. Invalid entities return 422 with validation errors and are not stored.

Example
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"]]]]}'
Example
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"}}}'

Definition lifecycle

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.

GET /validations

List current active definitions for the account.

GET /validations/{validation-id}

Fetch the current schema for one validation id.

DELETE /validations/{validation-id}

Retire a validation when it should no longer be listed or used by new writes.