Parsing a JSON string with zod #2215
-
|
I'm tired of writing the same try-catch code over and over again to parse JSON strings, and would love to parse it with something zod-like so it fits with the rest of my code. This is what I've come up with so far: const jsonSchema = z.string().refine((value) => {
try {
JSON.parse(value);
return true;
} catch (_) {
return false;
}
}).transform((value) => JSON.parse(value));Now I can do this: jsonSchema.parse('{"hello": "world"}') // {hello: "world"}
jsonSchema.safeParse('}') // {success: false, error: ZodError[...]}
jsonSchema.parse('}') // throws ZodErrorThis works great, awesome! But is there a way I can avoid calling |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 7 replies
-
Beta Was this translation helpful? Give feedback.
-
|
Just adding an alternative method of using const parseJsonPreprocessor = (value: any, ctx: z.RefinementCtx) => {
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch (e) {
ctx.addIssue({
code: ZodIssueCode.custom,
message: (e as Error).message,
});
}
}
return value;
};This can then be reused in multiple schemas like.. const someObjectShapeSchema = z.object({
foo: 'bar',
});
const someObjectSchema = z.preprocess(parseJsonPreprocessor, someObjectShapeSchema);
// Use as you normally would
someObjectSchema.parse('{"foo":"bar"}'); // { foo: 'bar' } |
Beta Was this translation helpful? Give feedback.
-
|
Zod v4 now has an inbuilt z.json() type. |
Beta Was this translation helpful? Give feedback.
-
|
With zod 4 it's possible to use const jsonString = z.string().pipe(
z.preprocess((input, ctx) => {
try {
return JSON.parse(input);
} catch (_) {
ctx.issues.push({ code: "custom", message: "Invalid JSON", input });
return z.NEVER;
}
}, z.json()),
);
jsonString.parse('{"omega":"kappa","number":42}');If you expect your json to be in a particular format, you can replace the const validator = z.object({
omega: z.string(),
number: z.number(),
});
const jsonString = z.string().pipe(
z.preprocess((input, ctx) => {
try {
return JSON.parse(input);
} catch (_) {
ctx.issues.push({ code: "custom", message: "Invalid JSON", input });
return z.NEVER;
}
}, validator),
);
jsonString.parse('{"omega":"kappa","number":42}'); |
Beta Was this translation helpful? Give feedback.
-
|
With Zod v4.1, you can do the following: const jsonToObject = jsonCodec(z.object({ name: z.string(), age: z.number() }));
jsonToObject.decode('{"name":"Alice","age":30}');
// => { name: "Alice", age: 30 }
jsonToObject.encode({ name: "Bob", age: 25 });
// => '{"name":"Bob","age":25}'
jsonToObject.decode('~~invalid~~');
// ZodError: [
// {
// "code": "invalid_format",
// "format": "json",
// "path": [],
// "message": "Unexpected token '~', \"~~invalid~~\" is not valid JSON"
// }
// ]const jsonCodec = <T extends z.core.$ZodType>(schema: T) =>
z.codec(z.string(), schema, {
decode: (jsonString, ctx) => {
try {
return JSON.parse(jsonString);
} catch (err: any) {
ctx.issues.push({
code: "invalid_format",
format: "json",
input: jsonString,
message: err.message,
});
return z.NEVER;
}
},
encode: (value) => JSON.stringify(value),
}); |
Beta Was this translation helpful? Give feedback.
https://github.com/JacobWeisenburger/zod_utilz#stringtojson