blomqma / next-rest-framework

Type-safe, self-documenting APIs for Next.js
https://next-rest-framework.vercel.app
Other
134 stars 17 forks source link

TypedNextRequest#json() returns an object that does not conform to the body schema #150

Closed aiwilliams closed 4 months ago

aiwilliams commented 4 months ago

Thanks for the great tool and all your work advancing it! Our team is particularly thankful for the recent work on the CLI and the stability that brought to generating the OpenAPI spec.

https://github.com/blomqma/next-rest-framework/blob/c35d4115649bea84315e7c72a6ff547d0270cfc1/packages/next-rest-framework/src/app-router/route.ts#L111 has the follow code:

            try {
              const json = await req.clone().json();

              const { valid, errors, data } = validateSchema({
                schema: bodySchema,
                obj: json
              });

              if (!valid) {
                return NextResponse.json(
                  {
                    message: DEFAULT_ERRORS.invalidRequestBody,
                    errors
                  },
                  {
                    status: 400
                  }
                );
              }

              reqClone = new NextRequest(reqClone.url, {
                ...reqClone,
                method: reqClone.method,
                headers: reqClone.headers,
                body: JSON.stringify(data)
              });
            } catch {
              return NextResponse.json(
                {
                  message: `${DEFAULT_ERRORS.invalidRequestBody} Failed to parse JSON body.`
                },
                {
                  status: 400
                }
              );
            }

validateSchema() returns the Zod#safeParse'd data, but the reqClone is created with body: JSON.stringify(data).

Given a body schema with a property such as this one:

targetEndDate: z.coerce.date()

The type returned by await req.json() claims that targetEndDate is a Date, but the type is actually string because it was serialized to JSON as an ISO date string.

This means the types are invalid. I had to re-parse the req.json() using the body schema to coerce it back to a Date.

It seems to me that since the framework has already read the body stream when the content type is application/json, and it has already parsed and validated the data, it would be good for req.json() to return that object so that it does actually conform to the schema and type it claims.

blomqma commented 4 months ago

Thanks for reporting, this is also fixed in v6.0.0-beta.2 now. The req.json() calls now return the raw data parsed using the Zod schema instead of the JSON-serialized data.