Reputation: 825
This might be a duplicate of Zod: Parse external JSON file
I have a function that expects a JSON string and parses it to a given type, inferred by a Zod schema
const createConfigurationFromJson = (content: string): Configuration => {
const rawConfiguration = JSON.parse(content);
return configurationSchema.parse(rawConfiguration);
};
This function might throw if the JSON content is invalid JSON or Zod throws a parse error. Without using another third party library, is it possible to let Zod parse the JSON string? So I can be sure there can only be a Zod error?
Upvotes: 4
Views: 12197
Reputation: 13283
If you want it completely in zod, before you can send that to the configurationSchema
, you need to transform the string content
to an object, and add an issue if and only if parsing the JSON fails. Then you can use .pipe
to pass that to configurationSchema
.
const configurationSchema = z.object({
name: z.string(),
version: z.string(),
description: z.string(),
});
type Configuration = z.infer<typeof configurationSchema>;
const createConfigurationFromJson = (content: string): Configuration => {
return z
.string()
.transform((_, ctx) => {
try {
return JSON.parse(content);
} catch (error) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'invalid json',
});
return z.never;
}
})
.pipe(configurationSchema)
.parse(content);
};
When tested with
const configuration1 = createConfigurationFromJson(`{
"name": "my-app",
"version": "1.0.0",
"description": "My awesome app"
}`);
const configuration2 = createConfigurationFromJson(`{
"banana": "🍌"
}`);
const configuration3 = createConfigurationFromJson(`{
fiadsjfoiajsdoivjdaoij
`);
it outputs the success and errors as
configuration1 {
name: "my-app",
version: "1.0.0",
description: "My awesome app"
}
configuration2 159 | const json = JSON.stringify(obj, null, 2);
160 | return json.replace(/"([^"]+)":/g, "$1:");
161 | };
162 | class ZodError extends Error {
163 | constructor(issues) {
164 | super();
^
ZodError: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"name"
],
"message": "Required"
},
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"version"
],
"message": "Required"
},
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"description"
],
"message": "Required"
}
]
errors: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"name"
],
"message": "Required"
},
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"version"
],
"message": "Required"
},
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"description"
],
"message": "Required"
}
]
at new ZodError (/Users/sgunter/code/zod-parse-json/node_modules/zod/lib/index.mjs:164:8)
at /Users/sgunter/code/zod-parse-json/node_modules/zod/lib/index.mjs:537:30
at parse (/Users/sgunter/code/zod-parse-json/node_modules/zod/lib/index.mjs:636:14)
at /Users/sgunter/code/zod-parse-json/index.ts:46:25
configuration3 159 | const json = JSON.stringify(obj, null, 2);
160 | return json.replace(/"([^"]+)":/g, "$1:");
161 | };
162 | class ZodError extends Error {
163 | constructor(issues) {
164 | super();
^
ZodError: [
{
"code": "custom",
"message": "invalid json",
"fatal": true,
"path": []
}
]
errors: [
{
"code": "custom",
"message": "invalid json",
"fatal": true,
"path": []
}
]
at new ZodError (/Users/sgunter/code/zod-parse-json/node_modules/zod/lib/index.mjs:164:8)
at /Users/sgunter/code/zod-parse-json/node_modules/zod/lib/index.mjs:537:30
at parse (/Users/sgunter/code/zod-parse-json/node_modules/zod/lib/index.mjs:636:14)
at /Users/sgunter/code/zod-parse-json/index.ts:55:25
Upvotes: 10
Reputation: 4991
There doesn't seem to be a package for that. In theory, such a package would do barely more than what you're already doing.
Maybe you could surround the json parsing with a try catch block, and turn the generic error into a zod error?
Upvotes: 1