zod-search-params is a library for parsing and validating search params in the browser.
- Predictable output
- Type safety
- Easy to use
yarn add zod-search-paramsimport { parseSearchParams } from 'zod-search-params'; // by default this imports version for zod v3
// or
import { parseSearchParams } from 'zod-search-params/v3'; // specifically import version for zod v3
// or
import { parseSearchParams } from 'zod-search-params/v4'; // specifically import version for zod v4Do NOT use coerce in the schema, coerce is applied automatically (to prevent casting undefined to "undefined" etc.) for enabled types, when it's needed.
const schema = z.object({
search: z.string().catch(''),
page: z.number().catch(1),
});import { parseSearchParams } from 'zod-search-params';
const parsedSearchParams = parseSearchParams(schema, urlSearchParams);If all object properties within the zod schema are defined with .catch(), the output will always be an object with the same properties as the schema, but with the default values.
import { parseSearchParams } from 'zod-search-params';
const schema = z.object({
search: z.string().catch(''),
page: z.number().catch(1),
});
const parsedSearchParams = parseSearchParams(schema);
/*
typeof parsedSearchParams
{
search: string,
page: number,
}
*/If one or all object properties within the zod schema don't have .catch(), the output will be an object with the same properties as the schema or undefined. Where the undefined will return if parsing of the search params fail (for example passing string into a number).
import { parseSearchParams } from 'zod-search-params';
const schema = z.object({
search: z.string().catch(''),
page: z.number(),
});
const parsedSearchParams = parseSearchParams(schema);
/*
typeof parsedSearchParams
undefined | {
search: string,
page: number,
}
*/Using .optional() on a property will make the property optional, can be also chained with .default() to provide a default value.
import { parseSearchParams } from 'zod-search-params';
const schema = z.object({
search: z.string().catch(''),
page: z.number().optional().catch(undefined),
sort: z.string().optional().default('name').catch('name'),
});
const parsedSearchParams = parseSearchParams(schema);
/*
typeof parsedSearchParams
{
search: string,
page?: number,
sort: string,
}
*/import { URLSearchParams } from 'url';
const schema = z.object({
search: z.string().catch(''),
page: z.number().catch(1),
});
const objectParams = {
search: 'hello',
page: '2',
};
const urlParams = new URLSearchParams();
urlParams.append('search', 'hello');
urlParams.append('page', '2');
console.log(parseSearchParams(schema, objectParams));
console.log(parseSearchParams(schema, urlParams));
/*
OUTPUTS:
{
search: 'hello',
page: 2,
}
*/import { URLSearchParams } from 'url';
const schema = z.object({
tags: z.array(z.string()).catch([]),
ids: z.array(z.number()).catch([]),
});
const objectParams = {
tags: ['zod', 'typescript'],
ids: '42',
};
const urlParams = new URLSearchParams();
urlParams.append('tags', 'zod');
urlParams.append('tags', 'typescript');
urlParams.append('ids', '42');
console.log(parseSearchParams(schema, objectParams));
console.log(parseSearchParams(schema, urlParams));
/*
OUTPUTS:
{
tags: ['zod', 'typescript'],
ids: [42],
}
*/