Skip to content

Commit

Permalink
feat: add plugin signatures (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
Puppo authored Feb 15, 2024
1 parent b6bc770 commit 62dc659
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 2 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,29 @@ async function run() {

run();
```

## How to create a plugin?

```ts
import { z } from 'zod';
import { FastifyPluginAsyncZod } from 'fastify-type-provider-zod';

const plugin: FastifyPluginAsyncZod = async function (fastify, _opts) {
fastify.route({
method: 'GET',
url: '/',
// Define your schema
schema: {
querystring: z.object({
name: z.string().min(4),
}),
response: {
200: z.string(),
},
},
handler: (req, res) => {
res.send(req.query.name);
},
});
};
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"fastify": "^4.24.3",
"fastify-plugin": "^4.5.1",
"jest": "^29.7.0",
"oas-validator": "^5.0.8",
"prettier": "^2.7.1",
Expand Down
46 changes: 44 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import type { FastifySchema, FastifySchemaCompiler, FastifyTypeProvider } from 'fastify';
import type {
FastifyPluginAsync,
FastifyPluginCallback,
FastifyPluginOptions,
FastifySchema,
FastifySchemaCompiler,
FastifyTypeProvider,
RawServerBase,
RawServerDefault,
} from 'fastify';
import type { FastifySerializerCompiler } from 'fastify/types/schema';
import type { z, ZodAny, ZodTypeAny } from 'zod';
import type { ZodAny, ZodTypeAny, z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -136,3 +145,36 @@ export const serializerCompiler: FastifySerializerCompiler<ZodAny | { properties

throw new ResponseValidationError(result);
};

/**
* FastifyPluginCallbackZod with Zod automatic type inference
*
* @example
* ```typescript
* import { FastifyPluginCallbackZod } fromg "fastify-type-provider-zod"
*
* const plugin: FastifyPluginCallbackZod = (fastify, options, done) => {
* done()
* }
* ```
*/
export type FastifyPluginCallbackZod<
Options extends FastifyPluginOptions = Record<never, never>,
Server extends RawServerBase = RawServerDefault,
> = FastifyPluginCallback<Options, Server, ZodTypeProvider>;

/**
* FastifyPluginAsyncZod with Zod automatic type inference
*
* @example
* ```typescript
* import { FastifyPluginAsyncZod } fromg "fastify-type-provider-zod"
*
* const plugin: FastifyPluginAsyncZod = async (fastify, options) => {
* }
* ```
*/
export type FastifyPluginAsyncZod<
Options extends FastifyPluginOptions = Record<never, never>,
Server extends RawServerBase = RawServerDefault,
> = FastifyPluginAsync<Options, Server, ZodTypeProvider>;
102 changes: 102 additions & 0 deletions types/plugin.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { Http2Server } from 'http2';

import type { FastifyPluginAsync, FastifyPluginCallback } from 'fastify';
import Fastify from 'fastify';
import fp from 'fastify-plugin';
import { expectType } from 'tsd';
import { z } from 'zod';

import type { FastifyPluginAsyncZod, FastifyPluginCallbackZod } from '../src/index';

// Ensure the defaults of FastifyPluginAsyncZod are the same as FastifyPluginAsync
export const pluginAsyncDefaults: FastifyPluginAsync = async (fastify, options) => {
const pluginAsyncZodDefaults: FastifyPluginAsyncZod = async (fastifyWithZod, optionsZod) => {
expectType<(typeof fastifyWithZod)['server']>(fastify.server);
expectType<typeof optionsZod>(options);
};
fastify.register(pluginAsyncZodDefaults);
};

// Ensure the defaults of FastifyPluginAsyncZod are the same as FastifyPluginCallback
export const pluginCallbackDefaults: FastifyPluginCallback = async (fastify, options) => {
const pluginCallbackZodDefaults: FastifyPluginAsyncZod = async (fastifyWithZod, optionsZod) => {
expectType<(typeof fastifyWithZod)['server']>(fastify.server);
expectType<typeof optionsZod>(options);
};

fastify.register(pluginCallbackZodDefaults);
};

const asyncPlugin: FastifyPluginAsyncZod<{ optionA: string }, Http2Server> = async (
fastify,
options,
) => {
expectType<Http2Server>(fastify.server);

expectType<string>(options.optionA);

fastify.get(
'/',
{
schema: {
body: z.object({
x: z.string(),
y: z.number(),
z: z.boolean(),
}),
},
},
(req) => {
expectType<boolean>(req.body.z);
expectType<number>(req.body.y);
expectType<string>(req.body.x);
},
);
};

const callbackPlugin: FastifyPluginCallbackZod<{ optionA: string }, Http2Server> = (
fastify,
options,
done,
) => {
expectType<Http2Server>(fastify.server);

expectType<string>(options.optionA);

fastify.get(
'/',
{
schema: {
body: z.object({
x: z.string(),
y: z.number(),
z: z.boolean(),
}),
},
},
(req) => {
expectType<boolean>(req.body.z);
expectType<number>(req.body.y);
expectType<string>(req.body.x);
},
);
done();
};

const fastify = Fastify();

fastify.register(asyncPlugin);
fastify.register(callbackPlugin);

const asyncPluginHttpDefault: FastifyPluginAsyncZod<{ optionA: string }> = async (
fastify,
options,
) => {
expectType<(typeof fastify)['server']>(fastify.server);
expectType<typeof options>(options);
expectType<{ optionA: string }>(options);
};

fp(asyncPlugin);
fp(callbackPlugin);
fp(asyncPluginHttpDefault);

0 comments on commit 62dc659

Please sign in to comment.