middleware icon indicating copy to clipboard operation
middleware copied to clipboard

Zod-OpenAPI not performing strict validation on response schemas

Open Rick-Phoenix opened this issue 11 months ago • 6 comments

Which middleware has the bug?

@hono/zod-openapi

What version of the middleware?

0.18.3

What version of Hono are you using?

4.6.14

What runtime/platform is your app running on? (with version if possible)

Node 20.17.0

What steps can reproduce the bug?

  1. Create a select schema with drizzle-zod. Add a .omit() option to omit some fields and add .strict() to make sure that extra fields are not accepted.
  2. Assign the schema to a response with the createRoute API

What is the expected behavior?

  • When passing an object that has fields that are not included in the schema to c.json(), the response should be seen as invalid and throw a type error.

What do you see instead?

  • No error is shown, and the response is seen as valid.

Additional information

I have tested the schema and I can clearly see from the openAPI specs that "additionalProperties" is set to false. Also, I can see from the autocomplete on c.json() that the schema does indeed exclude the extra properties that I am passing.

However, I can still pass extra fields and I get no error. I only get an error if I am manually parsing the response with zod.

Rick-Phoenix avatar Dec 27 '24 17:12 Rick-Phoenix

Hi @Rick-Phoenix

Thank you for the issue. It is a known issue that the Zod OpenAPI can't validate the value of the response: https://github.com/honojs/middleware/issues/181

yusukebe avatar Dec 31 '24 10:12 yusukebe

function strictJSONResponse<
  C extends Context,
  S extends ZodSchema,
  U extends StatusCode
>(c: C, schema: S, data: Parameters<Context['json']>[0], statusCode: U) {
  const validatedResponse = schema.safeParse(data);

  if (!validatedResponse.success) {
    return c.json(
      {
        message: 'Strict response validation failed',
      },
      500
    );
  }

  return c.json(validatedResponse.data as z.infer<S>, statusCode);
}

worked for me. maybe we could make this a helper?

askorupskyy avatar Jan 07 '25 04:01 askorupskyy

Would that work with parseAsync too?

Rick-Phoenix avatar Jan 07 '25 09:01 Rick-Phoenix

@Rick-Phoenix yes just make your function async

askorupskyy avatar Jan 07 '25 13:01 askorupskyy

@askorupskyy

Ah, I'm also considering the same approach: using a helper to validate the data before c.json()! This approach may not be only Zod OpenAPI function, but we can make it a more general feature in the hono core package.

yusukebe avatar Jan 08 '25 10:01 yusukebe

I have extended the example code by @askorupskyy to give you IDE feedback when the passed in data is incorrect

import type { Context } from "hono";
import type { ContentfulStatusCode } from "hono/utils/http-status";
import type { z, ZodSchema } from "zod";

export function strictJSONResponse<
  C extends Context,
  S extends ZodSchema,
  D extends Parameters<Context["json"]>[0] & z.infer<S>,
  U extends ContentfulStatusCode
>(c: C, schema: S, data: D, statusCode?: U) {
  const validatedResponse = schema.safeParse(data);

  if (!validatedResponse.success) {
    return c.json(
      {
        message: "Strict response validation failed",
      },
      500
    );
  }

  return c.json(validatedResponse.data, statusCode);
}
Image

cephalization avatar May 18 '25 22:05 cephalization