{"id":15286112,"url":"https://github.com/muniftanjim/express-zod-openapi","last_synced_at":"2025-04-13T03:08:02.364Z","repository":{"id":66188089,"uuid":"446407788","full_name":"MunifTanjim/express-zod-openapi","owner":"MunifTanjim","description":"Express + Zod + OpenAPI","archived":false,"fork":false,"pushed_at":"2023-10-19T20:35:51.000Z","size":331,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-13T03:08:00.281Z","etag":null,"topics":["express","openapi","zod"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MunifTanjim.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-10T12:09:38.000Z","updated_at":"2024-09-22T20:28:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"0daf5394-1c79-4862-8071-9718e89deb57","html_url":"https://github.com/MunifTanjim/express-zod-openapi","commit_stats":{"total_commits":15,"total_committers":1,"mean_commits":15.0,"dds":0.0,"last_synced_commit":"6421a1e4647138d650cf416d408ea43440001815"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":"MunifTanjim/npm-package-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MunifTanjim%2Fexpress-zod-openapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MunifTanjim%2Fexpress-zod-openapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MunifTanjim%2Fexpress-zod-openapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MunifTanjim%2Fexpress-zod-openapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MunifTanjim","download_url":"https://codeload.github.com/MunifTanjim/express-zod-openapi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657918,"owners_count":21140846,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express","openapi","zod"],"created_at":"2024-09-30T15:10:30.036Z","updated_at":"2025-04-13T03:08:02.332Z","avatar_url":"https://github.com/MunifTanjim.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![GitHub Workflow Status: CI](https://img.shields.io/github/actions/workflow/status/MunifTanjim/express-zod-openapi/ci.yml?label=CI\u0026style=for-the-badge)](https://github.com/MunifTanjim/express-zod-openapi/actions/workflows/ci.yml)\n[![Version](https://img.shields.io/npm/v/express-zod-openapi?style=for-the-badge)](https://npmjs.org/package/express-zod-openapi)\n[![Coverage](https://img.shields.io/codecov/c/gh/MunifTanjim/express-zod-openapi?style=for-the-badge)](https://codecov.io/gh/MunifTanjim/express-zod-openapi)\n[![License](https://img.shields.io/github/license/MunifTanjim/express-zod-openapi?style=for-the-badge)](https://github.com/MunifTanjim/express-zod-openapi/blob/main/LICENSE)\n\n# Express + Zod + OpenAPI\n\nExpress + Zod + OpenAPI\n\n## Installation\n\n```sh\n# using yarn:\nyarn add express-zod-openapi\n\n# using npm:\nnpm install --save express-zod-openapi\n```\n\n## Usage\n\n```ts\nimport express from 'express'\nimport {\n  ExpressOpenAPI,\n  RequestValidationError,\n  ResponseValidationError,\n  SpecificationPlugin,\n} from 'express-zod-openapi'\nimport { z } from 'zod'\n\nconst expressOpenApi = new ExpressOpenAPI()\n\nconst specificationPlugin = SpecificationPlugin.create()\n\nconst specification = expressOpenApi.registerPlugin(specificationPlugin)\n\nconst app = express()\n\napp.use(express.json())\n\napp.post(\n  '/ping',\n  specification({\n    operationId: 'ping',\n    req: {\n      query: z.object({\n        count: z.preprocess((v: unknown) =\u003e {\n          const val = Number(v)\n          return Number.isNaN(val) ? v : val\n        }, z.number().int().describe('number of times ping will pong')),\n      }),\n      body: z.object({\n        type: z.enum(['plastic', 'rubber', 'wood']).default('rubber'),\n      }),\n    },\n    res: {\n      200: {\n        body: z.object({\n          pong: z.number().int(),\n        }),\n      },\n    },\n  }),\n  (req, res) =\u003e {\n    const { count } = req.query\n\n    res.status(200).json({\n      pong: count,\n    })\n  },\n)\n\napp.use((err, _req, res, next) =\u003e {\n  if (err instanceof RequestValidationError) {\n    res.status(400).json({\n      error: {\n        message: `Request Validation Error`,\n        details: err.validationError.errors.map(({ message, path }) =\u003e ({\n          message,\n          location: path.join('.'),\n          locationType: err.segment,\n        })),\n      },\n    })\n\n    return\n  }\n\n  if (err instanceof ResponseValidationError) {\n    console.error(err)\n\n    res.status(500).json({\n      error: {\n        message: `Response Validation Error`,\n      },\n    })\n\n    return\n  }\n\n  next(err)\n})\n\nconst specification = expressOpenApi.populateSpecification(app)\n```\n\n## Plugin\n\nYou get the following plugins out of the box:\n\n- `SpecificationPlugin`\n\nBut that's not the end of it. You can write you own `ExpressOpenAPIPlugin` to perform arbitrary changes to\nthe OpenAPI Specification for your express routes.\n\n**Plugin Example:**\n\n```ts\nimport type { Handler } from 'express'\nimport type { ExpressOpenAPIPlugin } from 'express-zod-openapi'\n\ntype GetAuthorizationMiddleware = (permissions: string[]) =\u003e Handler\n\ntype AuthorizationPlugin = ExpressOpenAPIPlugin\u003c\n  string[],\n  GetAuthorizationMiddleware\n\u003e\n\nexport const getAuthorizationPlugin = (): AuthorizationPlugin =\u003e {\n  const authorizationPlugin: AuthorizationPlugin = {\n    name: 'authorization-plugin',\n\n    getMiddleware: (internals, permissions): Handler =\u003e {\n      const middleware: Handler = async (req, res, next) =\u003e {\n        // do regular stuffs that you do in your authorization middleware\n\n        /*\n        const hasSufficientPermission = await checkUserPermission(\n          req.user,\n          permissions\n        )\n\n        if (!hasSufficientPermission) {\n          return res.status(403).json({\n            error: {\n              message: `Not Authorized`,\n            },\n          })\n        }\n        */\n\n        next()\n      }\n\n      // this will be available as a parameter to `processRoute`  function\n      internals.stash.store(middleware, permissions)\n\n      return middleware\n    },\n\n    processRoute: (specification, permissions, { path, method }) =\u003e {\n      specification.addPathItemOperationSecurityRequirement(path, method, {\n        BearerAuth: permissions,\n      })\n    },\n  }\n\n  return authorizationPlugin\n}\n```\n\n## License\n\nLicensed under the MIT License. Check the [LICENSE](./LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuniftanjim%2Fexpress-zod-openapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmuniftanjim%2Fexpress-zod-openapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuniftanjim%2Fexpress-zod-openapi/lists"}