middleware icon indicating copy to clipboard operation
middleware copied to clipboard

[zod-openapi] use coerce in query does not respond proper error message when corresponding param not provided

Open zhuscat opened this issue 1 year ago • 1 comments

When not using coerce:

common.openapi(
  createRoute({
    method: 'get',
    path: '/dev',
    request: {
      query: z.object({
        id: z.string(),
      }),
    },
    responses: {
      200: {
        description: 'get dev id',
        content: {
          'application/json': {
            schema: z.object({
              id: z.string(),
            }),
          },
        },
      },
    },
  }),
  async (c) => {
    const { id } = c.req.valid('query')

    return c.json(
      {
        id: '123',
      },
      200,
    )
  },
)

request http://localhost:3000/dev respond with:

{
    "success": false,
    "error": {
        "issues": [
            {
                "code": "invalid_type",
                "expected": "string",
                "received": "undefined",
                "path": [
                    "id"
                ],
                "message": "Required"
            }
        ],
        "name": "ZodError"
    }
}

When using coerce:

common.openapi(
  createRoute({
    method: 'get',
    path: '/dev',
    request: {
      query: z.object({
        id: z.coerce.bigint(),
      }),
    },
    responses: {
      200: {
        description: 'get dev id',
        content: {
          'application/json': {
            schema: z.object({
              id: z.string(),
            }),
          },
        },
      },
    },
  }),
  async (c) => {
    const { id } = c.req.valid('query')

    return c.json(
      {
        id: '123',
      },
      200,
    )
  },
)

request http://localhost:3000/dev respond with:

Internal Server Error

zhuscat avatar Jul 10 '24 12:07 zhuscat

Hi @zhuscat

This a Zod matter and a Zod's limitation, and you can write like the following:

const schema = app.openapi(
  createRoute({
    method: 'get',
    path: '/dev',
    request: {
      query: z.object({
        id: z.any().transform((value, ctx) => {
          try {
            return BigInt(value)
          } catch (error) {
            ctx.addIssue({
              code: 'invalid_type',
              expected: 'unknown',
              received: value,
              message: `Can't be parsed to BigInt`
            })
          }
        })
      })
    },
// ...

These are good references for you:

  • https://github.com/colinhacks/zod/discussions/1897
  • https://github.com/colinhacks/zod/discussions/1856

yusukebe avatar Jul 21 '24 11:07 yusukebe