Skip to content

Validation Results and Error Helpers

The schema operation methods return an object with two properties: validatedObject and errors.

The validatedObject

This object contains the data after all casting and transformations have been applied. It's the "clean" version of your input that you should use in the rest of your application (e.g., to save to a database).

The errors Object

This is your primary tool for handling validation failures.

  • It's a Map, Not an Array: The errors object is a map where keys are the field names that failed. This allows you to instantly check if a specific field has an error: if (errors.age) { ... }.
  • Rich Error Structure: Each error in the map is a detailed object: { code, message, params }.
  • Nested paths stay flat: Nested fields are reported with dotted paths such as workspace.slug or roles.2.id. That keeps the external error contract simple even when schemas are recursive.

Let's look at an example with invalid data:

javascript
const invalidInput = {
  username: 'Al', // Fails 'minLength: 3'
  // email is missing, fails 'required: true'
  age: 16 // Fails 'min: 18'
};

const { validatedObject, errors } = userSchema.create(invalidInput);

console.log(JSON.stringify(errors, null, 2));

The output would look like this:

json
{
  "username": {
    "field": "username",
    "code": "MIN_LENGTH",
    "message": "Length must be at least 3 characters.",
    "params": { "min": 3, "actual": 2 }
  },
  "email": {
    "field": "email",
    "code": "REQUIRED",
    "message": "Field is required",
    "params": {}
  },
  "age": {
    "field": "age",
    "code": "MIN_VALUE",
    "message": "Value must be at least 18.",
    "params": { "min": 18, "actual": 16 }
  }
}
  • code: A stable, machine-readable string. Use this in your code for logic (if (err.code === 'MIN_LENGTH')).
  • message: A human-readable message, great for developers or for displaying directly to users in simple cases.
  • params: Extra context about the failure. This is incredibly useful for creating dynamic error messages (e.g., "You entered 2 characters, but a minimum of 3 is required.").

Error helper utilities

If you want a few adapter-friendly utilities around that flat error map, import them directly:

javascript
import { createSchema, getError, hasError, nestErrors, flattenErrors } from 'json-rest-schema'

getError(errors, path) reads one dotted-path error:

javascript
const slugError = getError(errors, 'workspace.slug')

hasError(errors, path) is the small boolean version:

javascript
const showSlugError = hasError(errors, 'workspace.slug')

nestErrors(errors) converts the flat map into a nested object/array shape for form libraries that prefer nested field errors:

javascript
nestErrors({
  'workspace.slug': {
    field: 'workspace.slug',
    code: 'MIN_LENGTH',
    message: 'Length must be at least 3 characters.',
    params: { min: 3, actual: 1 }
  },
  'roles.2.label': {
    field: 'roles.2.label',
    code: 'REQUIRED',
    message: 'Field is required',
    params: {}
  }
})

Result:

javascript
{
  workspace: {
    slug: {
      field: 'workspace.slug',
      code: 'MIN_LENGTH',
      message: 'Length must be at least 3 characters.',
      params: { min: 3, actual: 1 }
    }
  },
  roles: [
    ,
    ,
    {
      label: {
        field: 'roles.2.label',
        code: 'REQUIRED',
        message: 'Field is required',
        params: {}
      }
    }
  ]
}

That keeps the runtime contract flat, while still making it easy to adapt into nested UI-state libraries.

flattenErrors(nestedErrors) does the reverse when a UI layer gives you nested field errors and you want to normalize them back into the library's flat contract:

javascript
flattenErrors({
  workspace: {
    slug: {
      field: 'workspace.slug',
      code: 'MIN_LENGTH',
      message: 'Length must be at least 3 characters.',
      params: { min: 3, actual: 1 }
    }
  },
  roles: [
    ,
    ,
    {
      label: {
        field: 'roles.2.label',
        code: 'REQUIRED',
        message: 'Field is required',
        params: {}
      }
    }
  ]
})

Result:

javascript
{
  'workspace.slug': {
    field: 'workspace.slug',
    code: 'MIN_LENGTH',
    message: 'Length must be at least 3 characters.',
    params: { min: 3, actual: 1 }
  },
  'roles.2.label': {
    field: 'roles.2.label',
    code: 'REQUIRED',
    message: 'Field is required',
    params: {}
  }
}

GPL-3.0-only