0.1.1 • Published 6 months ago

@node-openapi/fastify v0.1.1

Weekly downloads
-
License
MIT
Repository
-
Last release
6 months ago

@node-openapi/fastify

Fastify adapter for @node-openapi/core — define Zod-validated routes, generate OpenAPI 3.1 docs, and send type-safe responses in Fastify.

Read more in the core library docs.


Table of Contents


Installation

Install the adapter along with its peer dependencies:

# npm
npm install fastify @node-openapi/fastify

# yarn
yarn add fastify @node-openapi/fastify

# pnpm
pnpm add fastify @node-openapi/fastify

Ensure you have a compatible version of Fastify (v4+) and Zod (v3+).


Quick Start

Create a minimal Fastify server with a GET /ping route and serve the OpenAPI JSON at /docs.

import Fastify from 'fastify';
import { OpenAPIRouter, createRoute, z } from '@node-openapi/fastify';

const app = Fastify();

// 1. Initialize the router
const router = new OpenAPIRouter();

// 2. Define a simple ping route
const pingRoute = createRoute({
  method: 'get',
  path: '/ping', // OpenAPI path
  getRoutingPath: () => '/ping', // Fastify path
  request: {},
  responses: {
    200: {
      content: {
        'application/json': { schema: z.object({ message: z.string() }) },
      },
    },
  },
});

router.route(pingRoute, async ({ h }) => {
  h.json({ message: 'pong' });
});

// 3. Serve OpenAPI docs
router.doc('/docs', {
  openapi: '3.1.0',
  info: { title: 'API', version: '1.0.0' },
});

// 4. Register the router with the Fastify app
router.registerApp(app);

// 5. Start server
app.listen({ port: 3000 }, () => {
  console.log('šŸš€ Server running at http://localhost:3000');
  console.log('šŸ“– API docs available at http://localhost:3000/docs');
});

API Reference

new OpenAPIRouter(options?)

  • options.validateResponse?: boolean — (default true) Enable or disable runtime response validation against your OpenAPI schemas in the h helper.

.middleware(handler)

Register global middleware for all routes defined on this router instance and its children. The handler function receives request, reply, and an object containing context. The context object is shared across middlewares and the final route handler for a given request.

const router = new OpenAPIRouter<{ user?: { id: string } }>();

router.middleware(async (request, reply, { context }) => {
  const userId = request.headers['x-user-id'];
  if (typeof userId === 'string') {
    context.user = { id: userId };
  }
});

.route(routeConfig, handler)

Define a handler for a route. The handler will run after all middlewares and request validation. The handler will receive an object with the following properties:

  • request: the native Fastify request
  • reply: the native Fastify reply
  • input: validated request data (param, query, header, cookie, form, json)
  • context: any values attached by your middleware
  • h: a typed helper for sending json or text responses. The typing is based on the response schema in the route config. The helper will also validate the response data if the validateResponse option is enabled.
router.route(myRouteConfig, async ({ input, context, h }) => {
  // ... your logic ...
  // The data type is inferred by the status, and the default status is 200.
  h.json({ data: result }); // Responds with status 200 by default
  // h.json({ error: 'Not found' }, 404);
});

.use(path, subRouter)

Mount a child OpenAPIRouter under a base path and merge its OpenAPI definitions. Middlewares from the parent router will be applied to the sub-router's routes.

const adminRouter = new OpenAPIRouter();
// Define routes on adminRouter...
router.use('/admin', adminRouter);

.doc(path, openapiConfig)

Serve the merged OpenAPI document as JSON at path.

router.doc('/openapi.json', {
  openapi: '3.1.0',
  info: { title: 'My Service', version: '1.2.3' },
});

.registerApp(app)

Registers all defined routes and middlewares with the provided Fastify application instance. This method should be called after all routes, middlewares, and sub-routers have been defined.

const app = Fastify();
const router = new OpenAPIRouter();
// ... define routes, middlewares, use sub-routers ...
router.registerApp(app);

createRoute

Re-exported helper from @node-openapi/core to define RouteConfig objects. It requires a getRoutingPath() method that returns the Fastify-specific path string (e.g., using :param for route parameters).

const articleRoute = createRoute({
  method: 'get',
  path: '/articles/{slug}', // OpenAPI path
  getRoutingPath: () => '/articles/:slug', // Fastify path
  request: {
    params: z.object({ slug: z.string() }),
  },
  // ...responses
});

z

Re-exported Zod instance from @node-openapi/core for defining schemas. It has additional types for OpenAPI documentation under .openapi(). You can read more about the options from @asteasolutions/zod-to-openapi.

const userSchema = z
  .object({
    id: z.string(),
    name: z.string(),
  })
  .openapi('User');

Configuration

  • Response validation: disable by new OpenAPIRouter({ validateResponse: false }).
  • Path parameters: Remember that createRoute's path is for OpenAPI (e.g., /users/{id}), while getRoutingPath() is for Fastify (e.g., /users/:id).

Examples

See a complete example with authentication and CRUD routes in the examples/fastify folder:

examples/fastify/
ā”œā”€ package.json
ā”œā”€ tsconfig.json
└─ src/
   ā”œā”€ factories.ts        # auth middleware factories
   ā”œā”€ controller/
   │  ā”œā”€ articles.controller.ts
   │  ā”œā”€ user.controller.ts
   │  └─ ... (other controllers)
   ā”œā”€ routes/
   │  └─ articles.routes.ts
   └─ index.ts            # main Fastify server setup

Advanced Usage

  • Context Extension: Use .extend() on a router to create derived router instances with extended TContext types. This is useful for gradually adding typed properties to the context through middlewares.
  • Error handling: Zod validation errors or errors thrown in handlers are caught by Fastify's setErrorHandler. You can customize this to format error responses. See the example index.ts.
  • Middleware Ordering: Middlewares registered with .middleware() are applied in the order they are defined. They run before the route's input validation and the main handler.

License

This project is licensed under the MIT License. See the LICENSE file for details.