A
arktype3w ago
IOM

Is there an equivalent of zod.safeParse() for parsing incoming JSON requests?

Most people that I know that use Zod, use it mainly to parse incoming JSON request data into a schema. After reading through the docs I couldn't find anything that's really the equivalent of these methods, but wasn't sure if I'm just blind? Generic example: import { z } from 'zod' const userDto = z.object({
firstName: z.string(), lastName: z.string(), birthDay: z.string().optional(), phone: z.string().optional() }); const handler = (request) => { const parseResult = userDto.safeParse(request?.body) if (parseResult.error) { //extract error fields and error messages and return the api response to the user } }
6 Replies
ssalbdivad
ssalbdivad3w ago
If your goal is to ensure additional keys are removed you can use onUndeclaredKey either per-object or globally: https://arktype.io/docs/objects#properties-undeclared https://arktype.io/docs/configuration#onundeclaredKey
IOM
IOMOP3w ago
Hey thanks for the links. Ultimate goal is really to parse the JSON string into a Javascript object of the expected schema
ssalbdivad
ssalbdivad3w ago
Invoking the top-level type you define will give you valid output data or an ArkErrors instance, is that what you want? I guess this section of the intro seems to parallel your example specifically: https://arktype.io/docs/intro/your-first-type
const user = type({
name: "string",
// nested definitions don't need to be wrapped
device: {
platform: "'android' | 'ios'",
"versions?": "(number | string)[]"
}
})

const out = user({
name: "Alan Turing",
device: {
platform: "enigma",
versions: [0, "1", 0n]
}
})

if (out instanceof type.errors) {
// hover out.summary to see validation errors
console.error(out.summary)
} else {
// hover out to see your validated data
console.log(`Hello, ${out.name}`)
}
const user = type({
name: "string",
// nested definitions don't need to be wrapped
device: {
platform: "'android' | 'ios'",
"versions?": "(number | string)[]"
}
})

const out = user({
name: "Alan Turing",
device: {
platform: "enigma",
versions: [0, "1", 0n]
}
})

if (out instanceof type.errors) {
// hover out.summary to see validation errors
console.error(out.summary)
} else {
// hover out to see your validated data
console.log(`Hello, ${out.name}`)
}
IOM
IOMOP3w ago
const carDto = z.object({
make: z.string(),
model: z.string(),
year: z.number(),
})

export const userDTO = z.object({
firstName: z.string(),
lastName: z.string(),
birthDate: z.string().date().optional(),
phoneNumber: z.string().optional(),
car: carDto
});

const body = {
firstName: 'john',
lastName: 'doe',
birthDate: '1990-01-01',
phoneNumber: 7,
car: {
make: 10000,
model: 'Camry',
year: 2000
}
}

const parseResult = userDTO.safeParse(body);

if (parseResult.error) {
console.error(parseResult.error.issues)
}
const carDto = z.object({
make: z.string(),
model: z.string(),
year: z.number(),
})

export const userDTO = z.object({
firstName: z.string(),
lastName: z.string(),
birthDate: z.string().date().optional(),
phoneNumber: z.string().optional(),
car: carDto
});

const body = {
firstName: 'john',
lastName: 'doe',
birthDate: '1990-01-01',
phoneNumber: 7,
car: {
make: 10000,
model: 'Camry',
year: 2000
}
}

const parseResult = userDTO.safeParse(body);

if (parseResult.error) {
console.error(parseResult.error.issues)
}
so pretend the user had to provide something of this shape above with safe parse you can get the path, error code, the expected, and received, so you can provide the user a more "structured" or customizable error response like:
{ "field": "phoneNumber", code: "invalid_type", message: "expected string, got number" }
{ "field": "phoneNumber", code: "invalid_type", message: "expected string, got number" }
{ "field": "car.make", code: "invalid_type", message: "expected string, got number" }
{ "field": "car.make", code: "invalid_type", message: "expected string, got number" }
the reason that this is important is because with this more structured error message, API users can better translate this to a form. They can present the relevant errors under the phoneNumber field in the form, and in the car.make field in the form with the out.summary i was messing with earlier I only saw the message summary but didnt see any structured way to get things like the effected field, the error code, etc "car.make must be a string (was a number)" "phoneNumber must be a string (was a number)"
No description
ssalbdivad
ssalbdivad3w ago
The actual value returned is an ArkErrors array. It has a .summary which is what you see there, but you can also iterate over it and introspect errors by code via e.g. .hasCode("min"). Also you may find the error config useful for customizing messages https://arktype.io/docs/configuration#errors
IOM
IOMOP3w ago
ahhh okay got it, thanks! Will check it out

Did you find this page helpful?