Home > OS >  How to "deep" parse schema that contains JSON string, using Zod?
How to "deep" parse schema that contains JSON string, using Zod?

Time:09-06

I'm using Zod to validate HTTP request that contains JSON data. Currently, I'm using a pattern like the one that follows (simplified, for readability):

const z = require('zod')
const payloadSchema = z.object({ name: z.string(), age: z.number().min(18) })
const requestSchema = z.object({ payload: z.string() })
// ...

const req = requestSchema.parse(request)
const raw = JSON.parse(req.payload)
const payload = payloadSchema.parse(raw)

console.log(payload.name) // << this is what I'm interested into

Does Zod provide a more strait-forward way to deep parse a shape that contains JSON string that I don't know of?

const z = require('zod')
const payloadSchema = z.object({ name: z.string(), age: z.number().min(18) })
const requestSchema = z.object({ payload: z.string().json(payloadSchema) })
// ...

const req = requestSchema.parse(request)
console.log(req.payload.name) // << this is what I'm interested into

CodePudding user response:

I think the way you are doing it is the only way if the json hasn't already been parsed. It seems weird that you would have a request schema (that is perhaps checking the request object returned from the library you are using to invoke the HTTP call) that is an object but the payload hasn't been JSON parsed yet.

Here's the runkit of your code sample: https://runkit.com/robert-rendell-the/6311cbb991ef9900086d4971

Some libraries (Nest.js) will json parse the payload when the HTTP request arrives so you wouldn't need that JSON parsing step

I'm assuming this is what your request looks like when it arrives:

{ payload: "{ name: '', age: 18}" }

Ideally you want something like Nest to do the parsing so your zod schema / zod parsing is as straight forward as this:

const z = require('zod')
const payloadSchema = z.object({ name: z.string(), age: z.number().min(18) })
const requestSchema = z.object({ payload: payloadSchema })
// ...


const req = requestSchema.parse({ payload: { name: '', age: 18}})
console.log(req.payload.name)

CodePudding user response:

According to the response of Zod's author, in GitHub (here)

The recommended approach here is to use preprocess to parse the payload before validation.

const z = require('zod')
const payloadSchema = z.object({ name: z.string(), age: z.number().min(18) })
const requestSchema = z.object({
  payload: z.preprocess((val) => JSON.parse(val), payloadSchema),
})

const req = requestSchema.parse({payload:'{"name": "Beth", "age": 20}'})
// req.payload.name === Beth
// req.payload.age === 20

(code edited for clarity)

  • Related