Skip to content

Commit

Permalink
Update serialization logic (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
samchungy authored Jan 25, 2025
1 parent df8ae4f commit 0350105
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 1 deletion.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ const customSerializerCompiler = createSerializerCompiler({
});
```

By default, this library assumes that if a response schema provided is not a Zod Schema, it is a JSON Schema and will naively pass it straight into `fast-json-stringify`. This will not work in conjunction with Fastify's schema registration.

If you have other routes with response schemas which are not Zod Schemas, you can supply a `fallbackSerializer` to `createSerializerCompiler`.

```ts
const customSerializerCompiler = createSerializerCompiler({
fallbackSerializer: ({ schema, url, method }) => customSerializer(schema),
});
```

Please note: the `responses`, `parameters` components do not appear to be supported by the `@fastify/swagger` library.

### Create Document Options
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@crackle/cli": "0.15.5",
"@fastify/swagger": "9.4.2",
"@fastify/swagger-ui": "5.2.1",
"@fastify/under-pressure": "9.0.3",
"@types/node": "22.10.7",
"eslint-plugin-zod-openapi": "1.0.0",
"fastify": "5.2.1",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 68 additions & 0 deletions src/serializerCompiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'zod-openapi/extend';

import UnderPressure from '@fastify/under-pressure';
import fastify from 'fastify';
import { z } from 'zod';
import type { ZodOpenApiResponsesObject } from 'zod-openapi';
Expand Down Expand Up @@ -74,6 +76,72 @@ describe('serializerCompiler', () => {
expect(result.json()).toEqual({ jobId: '60002023' });
});

it('should handle a route with a JSON schema', async () => {
const app = fastify();

app.setSerializerCompiler(serializerCompiler);
app.post(
'/',
{
schema: {
response: {
200: {
type: 'object',
properties: {
jobId: { type: 'string' },
},
},
},
},
},
async (_req, res) =>
res.send({
jobId: '60002023',
}),
);

await app.ready();

const result = await app.inject().post('/');

expect(result.json()).toEqual({ jobId: '60002023' });
});

it('should work with under pressure', async () => {
const app = fastify();

app.register(UnderPressure, {
exposeStatusRoute: '/status/health-check',
healthCheck: () => Promise.resolve(true),
});
app.setSerializerCompiler(serializerCompiler);
app.post(
'/',
{
schema: {
response: {
200: {
type: 'object',
properties: {
jobId: { type: 'string' },
},
},
},
},
},
async (_req, res) =>
res.send({
jobId: '60002023',
}),
);

await app.ready();

const result = await app.inject().get('/status/health-check');

expect(result.json()).toEqual({ status: 'ok' });
});

it('should fail an invalid response', async () => {
const app = fastify();

Expand Down
11 changes: 10 additions & 1 deletion src/serializerCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@ import type { FastifySerializerCompiler } from 'fastify/types/schema';
import type { ZodType, ZodTypeAny } from 'zod';
import { createSchema } from 'zod-openapi';

import { isZodType } from './transformer';
import { ResponseSerializationError } from './validationError';

export interface SerializerOptions {
components?: Record<string, ZodTypeAny>;
stringify?: (value: unknown) => string;
fallbackSerializer?: FastifySerializerCompiler<ZodType>;
}

export const createSerializerCompiler =
(opts?: SerializerOptions): FastifySerializerCompiler<ZodType> =>
({ schema, method, url }) => {
(routeSchema) => {
const { schema, url, method } = routeSchema;
if (!isZodType(schema)) {
return opts?.fallbackSerializer
? opts.fallbackSerializer(routeSchema)
: fastJsonStringify(schema);
}

let stringify = opts?.stringify;
if (!stringify) {
const { schema: jsonSchema, components } = createSchema(schema, {
Expand Down

0 comments on commit 0350105

Please sign in to comment.