baitendbidz
baitendbidz

Reputation: 825

Is Zod able to parse content of JSON files?

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

Answers (2)

Samathingamajig
Samathingamajig

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

Vivick
Vivick

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

Related Questions