{"id":21468391,"url":"https://github.com/trpc/trpc-openapi","last_synced_at":"2025-09-03T01:04:52.276Z","repository":{"id":37673851,"uuid":"488581282","full_name":"trpc/trpc-openapi","owner":"trpc","description":"OpenAPI support for tRPC 🧩","archived":true,"fork":false,"pushed_at":"2024-11-19T18:07:10.000Z","size":4788,"stargazers_count":2233,"open_issues_count":100,"forks_count":152,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-11-19T19:24:39.574Z","etag":null,"topics":["nodejs","openapi","rest","swagger","trpc","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/trpc-openapi","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/trpc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"jlalmes"}},"created_at":"2022-05-04T12:33:51.000Z","updated_at":"2024-11-19T18:07:39.000Z","dependencies_parsed_at":"2024-01-13T17:37:33.694Z","dependency_job_id":"8e5af9f9-41b9-493a-826c-e43a5e8f4781","html_url":"https://github.com/trpc/trpc-openapi","commit_stats":{"total_commits":106,"total_committers":15,"mean_commits":7.066666666666666,"dds":0.3679245283018868,"last_synced_commit":"d1eab87f14fc4bf20b000dfc3ecb5fc5b105006b"},"previous_names":["prosepilot/trpc-openapi","jlalmes/trpc-openapi","trpc/trpc-openapi"],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trpc%2Ftrpc-openapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trpc%2Ftrpc-openapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trpc%2Ftrpc-openapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trpc%2Ftrpc-openapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trpc","download_url":"https://codeload.github.com/trpc/trpc-openapi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226022616,"owners_count":17561313,"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":["nodejs","openapi","rest","swagger","trpc","typescript"],"created_at":"2024-11-23T09:01:27.991Z","updated_at":"2024-11-23T09:02:38.959Z","avatar_url":"https://github.com/trpc.png","language":"TypeScript","funding_links":["https://github.com/sponsors/jlalmes"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003e [!NOTE]\n\u003e\n\u003e Repo is archived due to not having maintainers - feel free to contact us if you want to take over maintenance.\n\u003e\n\u003e Otherwise, we might reintroduce trpc-openapi to the world as a paid package.\n\u003e \n\u003e For now, look at https://www.npmjs.com/package/trpc-to-openapi for an alternative\n\n---\n\n\n![trpc-openapi](assets/trpc-openapi-readme.png)\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003etrpc-openapi\u003c/h1\u003e\n  \u003ca href=\"https://www.npmjs.com/package/trpc-openapi\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/trpc-openapi.svg?style=flat\u0026color=brightgreen\" target=\"_blank\" /\u003e\u003c/a\u003e\n  \u003ca href=\"./LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-black\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://trpc.io/discord\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/badge/chat-discord-blue.svg\" /\u003e\u003c/a\u003e\n  \u003cbr /\u003e\n  \u003chr /\u003e\n\u003c/div\u003e\n\n#### `trpc-openapi` is maintained by ProsePilot - simple, fast and free online [writing tools](https://www.prosepilot.com/tools).\n\n---\n\n## **[OpenAPI](https://swagger.io/specification/) support for [tRPC](https://trpc.io/)** 🧩\n\n- Easy REST endpoints for your tRPC procedures.\n- Perfect for incremental adoption.\n- OpenAPI version 3.0.3.\n\n## Usage\n\n**1. Install `trpc-openapi`.**\n\n```bash\n# npm\nnpm install trpc-openapi\n# yarn\nyarn add trpc-openapi\n```\n\n**2. Add `OpenApiMeta` to your tRPC instance.**\n\n```typescript\nimport { initTRPC } from '@trpc/server';\nimport { OpenApiMeta } from 'trpc-openapi';\n\nconst t = initTRPC.meta\u003cOpenApiMeta\u003e().create(); /* 👈 */\n```\n\n**3. Enable `openapi` support for a procedure.**\n\n```typescript\nexport const appRouter = t.router({\n  sayHello: t.procedure\n    .meta({ /* 👉 */ openapi: { method: 'GET', path: '/say-hello' } })\n    .input(z.object({ name: z.string() }))\n    .output(z.object({ greeting: z.string() }))\n    .query(({ input }) =\u003e {\n      return { greeting: `Hello ${input.name}!` };\n    });\n});\n```\n\n**4. Generate an OpenAPI document.**\n\n```typescript\nimport { generateOpenApiDocument } from 'trpc-openapi';\n\nimport { appRouter } from '../appRouter';\n\n/* 👇 */\nexport const openApiDocument = generateOpenApiDocument(appRouter, {\n  title: 'tRPC OpenAPI',\n  version: '1.0.0',\n  baseUrl: 'http://localhost:3000',\n});\n```\n\n**5. Add an `trpc-openapi` handler to your app.**\n\nWe currently support adapters for [`Express`](http://expressjs.com/), [`Next.js`](https://nextjs.org/), [`Serverless`](https://www.serverless.com/), [`Fastify`](https://www.fastify.io/), [`Nuxt`](https://nuxtjs.org/) \u0026 [`Node:HTTP`](https://nodejs.org/api/http.html).\n\n[`Fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [`Cloudflare Workers`](https://workers.cloudflare.com/) \u0026 more soon™, PRs are welcomed 🙌.\n\n```typescript\nimport http from 'http';\nimport { createOpenApiHttpHandler } from 'trpc-openapi';\n\nimport { appRouter } from '../appRouter';\n\nconst server = http.createServer(createOpenApiHttpHandler({ router: appRouter })); /* 👈 */\n\nserver.listen(3000);\n```\n\n**6. Profit 🤑**\n\n```typescript\n// client.ts\nconst res = await fetch('http://localhost:3000/say-hello?name=James', { method: 'GET' });\nconst body = await res.json(); /* { greeting: 'Hello James!' } */\n```\n\n## Requirements\n\nPeer dependencies:\n\n- [`tRPC`](https://github.com/trpc/trpc) Server v10 (`@trpc/server`) must be installed.\n- [`Zod`](https://github.com/colinhacks/zod) v3 (`zod@^3.14.4`) must be installed (recommended `^3.20.0`).\n\nFor a procedure to support OpenAPI the following _must_ be true:\n\n- Both `input` and `output` parsers are present AND use `Zod` validation.\n- Query `input` parsers extend `Object\u003c{ [string]: String | Number | BigInt | Date }\u003e` or `Void`.\n- Mutation `input` parsers extend `Object\u003c{ [string]: AnyType }\u003e` or `Void`.\n- `meta.openapi.method` is `GET`, `POST`, `PATCH`, `PUT` or `DELETE`.\n- `meta.openapi.path` is a string starting with `/`.\n- `meta.openapi.path` parameters exist in `input` parser as `String | Number | BigInt | Date`\n\nPlease note:\n\n- Data [`transformers`](https://trpc.io/docs/data-transformers) (such as `superjson`) are ignored.\n- Trailing slashes are ignored.\n- Routing is case-insensitive.\n\n## HTTP Requests\n\nProcedures with a `GET`/`DELETE` method will accept inputs via URL `query parameters`. Procedures with a `POST`/`PATCH`/`PUT` method will accept inputs via the `request body` with a `application/json` or `application/x-www-form-urlencoded` content type.\n\n### Path parameters\n\nA procedure can accept a set of inputs via URL path parameters. You can add a path parameter to any OpenAPI procedure by using curly brackets around an input name as a path segment in the `meta.openapi.path` field.\n\n### Query parameters\n\nQuery \u0026 path parameter inputs are always accepted as a `string`. This library will attempt to [coerce](https://github.com/colinhacks/zod#coercion-for-primitives) your input values to the following primitive types out of the box: `number`, `boolean`, `bigint` and `date`. If you wish to support others such as `object`, `array` etc. please use [`z.preprocess()`](https://github.com/colinhacks/zod#preprocess).\n\n```typescript\n// Router\nexport const appRouter = t.router({\n  sayHello: t.procedure\n    .meta({ openapi: { method: 'GET', path: '/say-hello/{name}' /* 👈 */ } })\n    .input(z.object({ name: z.string() /* 👈 */, greeting: z.string() }))\n    .output(z.object({ greeting: z.string() }))\n    .query(({ input }) =\u003e {\n      return { greeting: `${input.greeting} ${input.name}!` };\n    });\n});\n\n// Client\nconst res = await fetch('http://localhost:3000/say-hello/James?greeting=Hello' /* 👈 */, {\n  method: 'GET',\n});\nconst body = await res.json(); /* { greeting: 'Hello James!' } */\n```\n\n### Request body\n\n```typescript\n// Router\nexport const appRouter = t.router({\n  sayHello: t.procedure\n    .meta({ openapi: { method: 'POST', path: '/say-hello/{name}' /* 👈 */ } })\n    .input(z.object({ name: z.string() /* 👈 */, greeting: z.string() }))\n    .output(z.object({ greeting: z.string() }))\n    .mutation(({ input }) =\u003e {\n      return { greeting: `${input.greeting} ${input.name}!` };\n    });\n});\n\n// Client\nconst res = await fetch('http://localhost:3000/say-hello/James' /* 👈 */, {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ greeting: 'Hello' }),\n});\nconst body = await res.json(); /* { greeting: 'Hello James!' } */\n```\n\n### Custom headers\n\nAny custom headers can be specified in the `meta.openapi.headers` array, these headers will not be validated on request. Please consider using [Authorization](#authorization) for first-class OpenAPI auth/security support.\n\n## HTTP Responses\n\nStatus codes will be `200` by default for any successful requests. In the case of an error, the status code will be derived from the thrown `TRPCError` or fallback to `500`.\n\nYou can modify the status code or headers for any response using the `responseMeta` function.\n\nPlease see [error status codes here](src/adapters/node-http/errors.ts).\n\n## Authorization\n\nTo create protected endpoints, add `protect: true` to the `meta.openapi` object of each tRPC procedure. By default, you can then authenticate each request with the `createContext` function using the `Authorization` header with the `Bearer` scheme. If you wish to authenticate requests using a different/additional methods (such as custom headers, or cookies) this can be overwritten by specifying `securitySchemes` object.\n\nExplore a [complete example here](examples/with-nextjs/src/server/router.ts).\n\n#### Server\n\n```typescript\nimport { TRPCError, initTRPC } from '@trpc/server';\nimport { OpenApiMeta } from 'trpc-openapi';\n\ntype User = { id: string; name: string };\n\nconst users: User[] = [\n  {\n    id: 'usr_123',\n    name: 'James',\n  },\n];\n\nexport type Context = { user: User | null };\n\nexport const createContext = async ({ req, res }): Promise\u003cContext\u003e =\u003e {\n  let user: User | null = null;\n  if (req.headers.authorization) {\n    const userId = req.headers.authorization.split(' ')[1];\n    user = users.find((_user) =\u003e _user.id === userId);\n  }\n  return { user };\n};\n\nconst t = initTRPC.context\u003cContext\u003e().meta\u003cOpenApiMeta\u003e().create();\n\nexport const appRouter = t.router({\n  sayHello: t.procedure\n    .meta({ openapi: { method: 'GET', path: '/say-hello', protect: true /* 👈 */ } })\n    .input(z.void()) // no input expected\n    .output(z.object({ greeting: z.string() }))\n    .query(({ input, ctx }) =\u003e {\n      if (!ctx.user) {\n        throw new TRPCError({ message: 'User not found', code: 'UNAUTHORIZED' });\n      }\n      return { greeting: `Hello ${ctx.user.name}!` };\n    }),\n});\n```\n\n#### Client\n\n```typescript\nconst res = await fetch('http://localhost:3000/say-hello', {\n  method: 'GET',\n  headers: { Authorization: 'Bearer usr_123' } /* 👈 */,\n});\nconst body = await res.json(); /* { greeting: 'Hello James!' } */\n```\n\n## Examples\n\n_For advanced use-cases, please find examples in our [complete test suite](test)._\n\n#### With Express\n\nPlease see [full example here](examples/with-express).\n\n```typescript\nimport { createExpressMiddleware } from '@trpc/server/adapters/express';\nimport express from 'express';\nimport { createOpenApiExpressMiddleware } from 'trpc-openapi';\n\nimport { appRouter } from '../appRouter';\n\nconst app = express();\n\napp.use('/api/trpc', createExpressMiddleware({ router: appRouter }));\napp.use('/api', createOpenApiExpressMiddleware({ router: appRouter })); /* 👈 */\n\napp.listen(3000);\n```\n\n#### With Next.js\n\nPlease see [full example here](examples/with-nextjs).\n\n```typescript\n// pages/api/[...trpc].ts\nimport { createOpenApiNextHandler } from 'trpc-openapi';\n\nimport { appRouter } from '../../server/appRouter';\n\nexport default createOpenApiNextHandler({ router: appRouter });\n```\n\n#### With AWS Lambda\n\nPlease see [full example here](examples/with-serverless).\n\n```typescript\nimport { createOpenApiAwsLambdaHandler } from 'trpc-openapi';\n\nimport { appRouter } from './appRouter';\n\nexport const openApi = createOpenApiAwsLambdaHandler({ router: appRouter });\n```\n\n#### With Fastify\n\nPlease see [full example here](examples/with-fastify).\n\n```typescript\nimport { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';\nimport Fastify from 'fastify';\nimport { fastifyTRPCOpenApiPlugin } from 'trpc-openapi';\n\nimport { appRouter } from './router';\n\nconst fastify = Fastify();\n\nasync function main() {\n  await fastify.register(fastifyTRPCPlugin, { router: appRouter });\n  await fastify.register(fastifyTRPCOpenApiPlugin, { router: appRouter }); /* 👈 */\n\n  await fastify.listen({ port: 3000 });\n}\n\nmain();\n```\n\n## Types\n\n#### GenerateOpenApiDocumentOptions\n\nPlease see [full typings here](src/generator/index.ts).\n\n| Property          | Type                                   | Description                                             | Required |\n| ----------------- | -------------------------------------- | ------------------------------------------------------- | -------- |\n| `title`           | `string`                               | The title of the API.                                   | `true`   |\n| `description`     | `string`                               | A short description of the API.                         | `false`  |\n| `version`         | `string`                               | The version of the OpenAPI document.                    | `true`   |\n| `baseUrl`         | `string`                               | The base URL of the target server.                      | `true`   |\n| `docsUrl`         | `string`                               | A URL to any external documentation.                    | `false`  |\n| `tags`            | `string[]`                             | A list for ordering endpoint groups.                    | `false`  |\n| `securitySchemes` | `Record\u003cstring, SecuritySchemeObject\u003e` | Defaults to `Authorization` header with `Bearer` scheme | `false`  |\n\n#### OpenApiMeta\n\nPlease see [full typings here](src/types.ts).\n\n| Property       | Type                | Description                                                                                          | Required | Default                |\n| -------------- | ------------------- | ---------------------------------------------------------------------------------------------------- | -------- | ---------------------- |\n| `enabled`      | `boolean`           | Exposes this procedure to `trpc-openapi` adapters and on the OpenAPI document.                       | `false`  | `true`                 |\n| `method`       | `HttpMethod`        | HTTP method this endpoint is exposed on. Value can be `GET`, `POST`, `PATCH`, `PUT` or `DELETE`.     | `true`   | `undefined`            |\n| `path`         | `string`            | Pathname this endpoint is exposed on. Value must start with `/`, specify path parameters using `{}`. | `true`   | `undefined`            |\n| `protect`      | `boolean`           | Requires this endpoint to use a security scheme.                                                     | `false`  | `false`                |\n| `summary`      | `string`            | A short summary of the endpoint included in the OpenAPI document.                                    | `false`  | `undefined`            |\n| `description`  | `string`            | A verbose description of the endpoint included in the OpenAPI document.                              | `false`  | `undefined`            |\n| `tags`         | `string[]`          | A list of tags used for logical grouping of endpoints in the OpenAPI document.                       | `false`  | `undefined`            |\n| `headers`      | `ParameterObject[]` | An array of custom headers to add for this endpoint in the OpenAPI document.                         | `false`  | `undefined`            |\n| `contentTypes` | `ContentType[]`     | A set of content types specified as accepted in the OpenAPI document.                                | `false`  | `['application/json']` |\n| `deprecated`   | `boolean`           | Whether or not to mark an endpoint as deprecated                                                     | `false`  | `false`                |\n\n#### CreateOpenApiNodeHttpHandlerOptions\n\nPlease see [full typings here](src/adapters/node-http/core.ts).\n\n| Property        | Type       | Description                                            | Required |\n| --------------- | ---------- | ------------------------------------------------------ | -------- |\n| `router`        | `Router`   | Your application tRPC router.                          | `true`   |\n| `createContext` | `Function` | Passes contextual (`ctx`) data to procedure resolvers. | `false`  |\n| `responseMeta`  | `Function` | Returns any modifications to statusCode \u0026 headers.     | `false`  |\n| `onError`       | `Function` | Called if error occurs inside handler.                 | `false`  |\n| `maxBodySize`   | `number`   | Maximum request body size in bytes (default: 100kb).   | `false`  |\n\n---\n\n_Still using tRPC v9? See our [`.interop()`](examples/with-interop) example._\n\n## License\n\nDistributed under the MIT License. See LICENSE for more information.\n\n## Contact\n\nJames Berry - Follow me on Twitter [@jlalmes](https://twitter.com/jlalmes) 💚\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrpc%2Ftrpc-openapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrpc%2Ftrpc-openapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrpc%2Ftrpc-openapi/lists"}