Appearance
Validation
SchemaStack validates request data against your entity's column constraints before persisting. When validation fails, the API returns a 422 Unprocessable Entity response with per-field error details.
How It Works
Constraints defined on your columns (via the SchemaStack UI or API) are automatically enforced on every create and update request. No additional configuration is needed.
- Create (POST): All constraints are checked, and required fields (non-nullable columns) must be present.
- Update (PUT): Only the submitted fields are validated. Missing fields are not treated as errors (partial updates are allowed).
Validation Error Format
When one or more fields fail validation, the response includes a details array listing each error:
json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: 2 error(s)",
"details": [
{ "field": "email", "message": "must be a valid email address" },
{ "field": "name", "message": "name is required" }
]
}
}Constraint Types
| Type | Applies To | Description | Example Value |
|---|---|---|---|
REQUIRED | All | Value must be present on every write; the column may stay nullable in the database | — |
NOT_BLANK | String | Must not be blank or whitespace-only | — |
MIN_LENGTH | String | Minimum character length | "5" |
MAX_LENGTH | String | Maximum character length | "100" |
PATTERN | String | Must match a regex pattern | "^[A-Z]{3}$" |
EMAIL | String | Must be a valid email address | — |
URL | String | Must be a valid URL | — |
MIN | Number | Minimum numeric value | "0" |
MAX | Number | Maximum numeric value | "999" |
POSITIVE | Number | Must be greater than zero | — |
NEGATIVE | Number | Must be less than zero | — |
POSITIVE_OR_ZERO | Number | Must be zero or greater | — |
NEGATIVE_OR_ZERO | Number | Must be zero or less | — |
PAST | Date/Time | Must be in the past | — |
FUTURE | Date/Time | Must be in the future | — |
PAST_OR_PRESENT | Date/Time | Must be today or in the past | — |
FUTURE_OR_PRESENT | Date/Time | Must be today or in the future | — |
Cross-Field Rules
Entity-level constraints — rules that relate two or more columns, like start date before end date or at least one of email and phone — are enforced on API writes as well, with the same nine implemented types the app enforces.
- Create validates the payload, which is the complete row.
- Update validates the row as it will be stored — the merged state — because an update payload is partial and a rule comparing two fields may only see one of them in the request. You cannot update a row into violation through the field the rule does not mention.
Comparison rules skip when either field is null; presence rules treat an empty string as absent and zero or false as present. Violations return the same 422 envelope as column constraints, with the rule's custom message when one is set.
Built-In Checks
In addition to explicit constraints, the API automatically validates:
- Required fields: Non-nullable columns must be present on create requests.
- Column length: String values cannot exceed the column's defined
length. - Type matching: Values must be compatible with the column type (e.g., numbers for INTEGER columns, strings for VARCHAR).
Create vs. Update
| Check | Create (POST) | Update (PUT) |
|---|---|---|
| Required fields (non-nullable) | Enforced | Skipped |
| Type validation | Enforced | Enforced |
| Column length | Enforced | Enforced |
| Constraint rules | Enforced | Enforced |
Custom Error Messages
When defining constraints, you can optionally set a custom error message. If no custom message is set, a sensible default is used:
json
// Constraint with custom message
{
"type": "PATTERN",
"value": "^[A-Z]{3}-\\d{4}$",
"message": "Product code must follow the format ABC-1234"
}
// Default message: "must match pattern: ^[A-Z]{3}-\\d{4}$"Examples
Creating a Record with Validation Errors
bash
curl -X POST ".../api/v1/acme-corp/sales/products" \
-H "Authorization: Bearer sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"price": -5,
"sku": "invalid"
}'Response (422):
json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: 3 error(s)",
"details": [
{ "field": "name", "message": "name is required" },
{ "field": "price", "message": "must be positive" },
{ "field": "sku", "message": "must match pattern: ^[A-Z]{3}-\\d{4}$" }
]
}
}Updating with Partial Data (Valid)
bash
curl -X PUT ".../api/v1/acme-corp/sales/products/42" \
-H "Authorization: Bearer sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{ "price": 29.99 }'Response (200) — name is not required on update:
json
{
"data": {
"id": 42,
"name": "Widget",
"price": 29.99,
"sku": "WDG-0001"
}
}