cloudflare / chanfana

OpenAPI 3 and 3.1 schema generator and validator for Hono, itty-router and more!
https://chanfana.pages.dev
MIT License
302 stars 40 forks source link

Bug: chanfana assumes all instances of `ZodError` thrown from a route's `handle` method are 400 user request validation errors #166

Open ilyasotkov opened 1 month ago

ilyasotkov commented 1 month ago

Bug description: If a route's handle method throws a ZodError that's not coming from validateRequest, chanfana erroneously returns 400 to the user, also exposing the route's internal implementation details in the response body.

Desired behavior: only errors thrown from getValidatedData are assumed to be a user request validation error.

Example:

import { fromIttyRouter, OpenAPIRoute } from 'chanfana';
import { json, Router } from 'itty-router';
import { z } from 'zod';

const schema = z.object({ hello: z.string().default('world') });

export class MyRoute extends OpenAPIRoute {
  schema = {
    request: {
      body: {
        content: {
          'application/json': {
            schema,
          },
        },
      },
    },
    responses: {
      '201': {
        description: 'Return request body after validation',
        content: {
          'application/json': {
            schema,
          },
        },
      },
    },
  };

  async handle() {
    const data = await this.getValidatedData<typeof this.schema>();

    // Internal logic executed after successful user request validation
    const internalSchema = z.object({ internal: z.string().max(3) });
    internalSchema.parse({ internal: 'Highly senstive data' });

    return json(data.body);
  }
}

export default fromIttyRouter(Router()).post('/hello', MyRoute);

for all valid requests will always return 400 Bad Request

    {
      "errors": [
        {
          "code": "invalid_type",
          "expected": "string",
          "message": "Required",
          "path": [
            "internal",
          ],
          "received": "undefined",
        },
      ],
      "result": {},
      "success": false,
    }