Back to results
MunifTanjim/express-zod-openapi(opens in a new tab)
Language: TypeScript
Express + Zod + OpenAPI
- stars
- 6
- watchers
- 1
- forks
- 2
- open issues
- 0
- Last updated
- 10/20/2023
Language: TypeScript
Express + Zod + OpenAPI
Express + Zod + OpenAPI
# using yarn: yarn add express-zod-openapi # using npm: npm install --save express-zod-openapi
import express from 'express' import { ExpressOpenAPI, RequestValidationError, ResponseValidationError, SpecificationPlugin, } from 'express-zod-openapi' import { z } from 'zod' const expressOpenApi = new ExpressOpenAPI() const specificationPlugin = SpecificationPlugin.create() const specification = expressOpenApi.registerPlugin(specificationPlugin) const app = express() app.use(express.json()) app.post( '/ping', specification({ operationId: 'ping', req: { query: z.object({ count: z.preprocess((v: unknown) => { const val = Number(v) return Number.isNaN(val) ? v : val }, z.number().int().describe('number of times ping will pong')), }), body: z.object({ type: z.enum(['plastic', 'rubber', 'wood']).default('rubber'), }), }, res: { 200: { body: z.object({ pong: z.number().int(), }), }, }, }), (req, res) => { const { count } = req.query res.status(200).json({ pong: count, }) }, ) app.use((err, _req, res, next) => { if (err instanceof RequestValidationError) { res.status(400).json({ error: { message: `Request Validation Error`, details: err.validationError.errors.map(({ message, path }) => ({ message, location: path.join('.'), locationType: err.segment, })), }, }) return } if (err instanceof ResponseValidationError) { console.error(err) res.status(500).json({ error: { message: `Response Validation Error`, }, }) return } next(err) }) const specification = expressOpenApi.populateSpecification(app)
You get the following plugins out of the box:
SpecificationPluginBut that's not the end of it. You can write you own ExpressOpenAPIPlugin to perform arbitrary changes to
the OpenAPI Specification for your express routes.
Plugin Example:
import type { Handler } from 'express' import type { ExpressOpenAPIPlugin } from 'express-zod-openapi' type GetAuthorizationMiddleware = (permissions: string[]) => Handler type AuthorizationPlugin = ExpressOpenAPIPlugin< string[], GetAuthorizationMiddleware > export const getAuthorizationPlugin = (): AuthorizationPlugin => { const authorizationPlugin: AuthorizationPlugin = { name: 'authorization-plugin', getMiddleware: (internals, permissions): Handler => { const middleware: Handler = async (req, res, next) => { // do regular stuffs that you do in your authorization middleware /* const hasSufficientPermission = await checkUserPermission( req.user, permissions ) if (!hasSufficientPermission) { return res.status(403).json({ error: { message: `Not Authorized`, }, }) } */ next() } // this will be available as a parameter to `processRoute` function internals.stash.store(middleware, permissions) return middleware }, processRoute: (specification, permissions, { path, method }) => { specification.addPathItemOperationSecurityRequirement(path, method, { BearerAuth: permissions, }) }, } return authorizationPlugin }
Licensed under the MIT License. Check the LICENSE file for details.