1.0.0 • Published 2 years ago

zod-structured-error v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

zod-structured-error

Kneel before Zod!

A small library that converts Zod errors into structured objects. Zero dependencies, zero fuss.

npm version Build Status

Installation

npm install zod-structured-error

Zod is a peer dependency. Be sure it's already installed.

npm install zod

Usage

toStructuredError

declare function toStructuredError(
  error: ZodError<any>, 
  options?: ZodStructuredErrorOptions
): ZodStructuredError
  • error - A Zod error object
  • options - An optional options object
OptionTypeDefaultDescription
groupingunion ErrorGroupingjoinHow to handle multiple errors for the same path
joinDelimiterstring'; 'The delimiter to use when joining multiple errors. Ignored when grouping is not join
pathDelimiterstring'.'The delimiter to use when joining error path segments

ErrorGrouping

The grouping option determines how multiple errors for the same path are handled. The following values are available:

GroupingDescription
joinJoin multiple errors with a delimiter (default)
arrayRepresent errors as arrays
array-if-multipleRepresent errors as arrays, but only if there are multiple errors for the same path

ZodStructuredError

The ZodStructuredError return type is an alias for Record<string, string | string[]>

Example

import { z } from 'zod'
import { toStructuredError } from 'zod-structured-error'

const schema = z.object({
  label: z.string(),
  tags: z.array(z.string().nonempty()),
  nested: z.object({
    id: z.number().positive().multipleOf(10),
    value: z.string(),
  }),
  attributes: z.array(z.object({
    name: z.string(),
    value: z.string(),
  })),
})

const result = schema.safeParse({
  label: null,
  tags: ['foo', '', 'baz'],
  nested: {
    id: -22,
    value: 'Hello, world!',
  },
  attributes: [
    { name: 'foo', value: 'bar' },
    { name: 'baz', value: 'qux' },
  ],
})

if (!result.success) {
  const structured = toStructuredError(result.error)
  console.log(result.error)
  console.log(structured)
}

The Zod error for this example looks like this:

[
    {
      code: 'invalid_type',
      expected: 'string',
      received: 'null',
      path: [ 'label' ],
      message: 'Expected string, received null'
    },
    {
      code: 'too_small',
      minimum: 1,
      type: 'string',
      inclusive: true,
      exact: false,
      message: 'String must contain at least 1 character(s)',
      path: [ 'tags', 1 ]
    },
    {
      code: 'too_small',
      minimum: 0,
      type: 'number',
      inclusive: false,
      exact: false,
      message: 'Number must be greater than 0',
      path: [ 'nested', 'id' ]
    },
    {
      code: 'not_multiple_of',
      multipleOf: 10,
      message: 'Number must be a multiple of 10',
      path: [ 'nested', 'id' ]
    }
  ],

But the structured error looks simplifies the error and groups errors by path:

{
  'label': 'Expected string, received null',
  'tags.1': 'String must contain at least 1 character(s)',
  'nested.id': 'Number must be greater than 0; Number must be a multiple of 10'
}

Customization

By default, multiple errors for the same path are joined with a semicolon. You can change the delimiter:

const structured = toStructuredError(result.error, {
  joinDelimiter: ' | ',
})

// Outputs
{
  'label': 'Expected string, received null',
  'tags.1': 'String must contain at least 1 character(s)',
  'nested.id': 'Number must be greater than 0 | Number must be a multiple of 10'
}

Errors can be represented arrays instead of strings:

const structured = toStructuredError(result.error, {
  grouping: 'array',
})

// Outputs
{
  'label': [ 'Expected string, received null' ],
  'tags.1': [ 'String must contain at least 1 character(s)' ],
  'nested.id': [
    'Number must be greater than 0',
    'Number must be a multiple of 10'
  ]
}

Errors can be represented arrays, but only if there are multiple errors for the same path:

const structured = toStructuredError(result.error, {
  grouping: 'array-if-multiple',
})

// Outputs
{
  'label': 'Expected string, received null',
  'tags.1': 'String must contain at least 1 character(s)',
  'nested.id': [
    'Number must be greater than 0',
    'Number must be a multiple of 10'
  ]
}

Path segments are joined with a period by default. You can change the this:

const structured = toStructuredError(result.error, {
  pathDelimiter: '/',
})

// Outputs
{
  'label': 'Expected string, received null',
  'tags/1': 'String must contain at least 1 character(s)',
  'nested/id': 'Number must be greater than 0; Number must be a multiple of 10'
}

Changelog

You can find the changelog at CHANGELOG.md.

1.0.0

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago