Skip to content

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

TypeApplies ToDescriptionExample Value
REQUIREDAllValue must be present on every write; the column may stay nullable in the database
NOT_BLANKStringMust not be blank or whitespace-only
MIN_LENGTHStringMinimum character length"5"
MAX_LENGTHStringMaximum character length"100"
PATTERNStringMust match a regex pattern"^[A-Z]{3}$"
EMAILStringMust be a valid email address
URLStringMust be a valid URL
MINNumberMinimum numeric value"0"
MAXNumberMaximum numeric value"999"
POSITIVENumberMust be greater than zero
NEGATIVENumberMust be less than zero
POSITIVE_OR_ZERONumberMust be zero or greater
NEGATIVE_OR_ZERONumberMust be zero or less
PASTDate/TimeMust be in the past
FUTUREDate/TimeMust be in the future
PAST_OR_PRESENTDate/TimeMust be today or in the past
FUTURE_OR_PRESENTDate/TimeMust 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

CheckCreate (POST)Update (PUT)
Required fields (non-nullable)EnforcedSkipped
Type validationEnforcedEnforced
Column lengthEnforcedEnforced
Constraint rulesEnforcedEnforced

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

SchemaStack Documentation