{"_id":"@dum3ng/trpc-to-openapi","name":"@dum3ng/trpc-to-openapi","dist-tags":{"latest":"2.1.1"},"versions":{"2.1.1":{"name":"@dum3ng/trpc-to-openapi","version":"2.1.1","description":"tRPC OpenAPI","author":{"name":"mcampa"},"private":false,"license":"MIT","keywords":["trpc","openapi","swagger"],"homepage":"https://github.com/mcampa/trpc-to-openapi","repository":{"type":"git","url":"git+https://github.com/mcampa/trpc-to-openapi.git"},"bugs":{"url":"https://github.com/mcampa/trpc-to-openapi/issues"},"main":"dist/cjs/index.js","module":"dist/esm/index.mjs","typings":"dist/cjs/index.d.ts","exports":{".":{"require":"./dist/cjs/index.js","import":"./dist/esm/index.mjs","types":"./dist/cjs/index.d.ts"}},"workspaces":[".","examples/with-nextjs-appdir","examples/with-nextjs","examples/with-express","examples/with-interop","examples/with-serverless","examples/with-fastify","examples/with-nuxtjs"],"scripts":{"t":"jest","test":"tsc --noEmit && jest --verbose","lint":"eslint . --ext .ts","lint-fix":"eslint . --ext .ts --fix","format":"prettier --write ./src ./test ./examples","build":"npm test && rimraf dist && npm run build:cjs && npm run build:esm","build:cjs":"tsc -p tsconfig.build.cjs.json","build:esm":"tsc -p tsconfig.build.esm.json","postbuild":"node rename.js"},"peerDependencies":{"@trpc/server":"^11.0.0-rc.648","zod":"^3.23.8","zod-openapi":"^4.1.0"},"dependencies":{"co-body":"^6.1.0","h3":"^1.6.4","openapi3-ts":"4.4.0"},"devDependencies":{"@trpc/client":"^11.0.0-rc.648","@types/aws-lambda":"^8.10.115","@types/co-body":"^6.1.0","@types/express":"^4.17.17","@types/jest":"^29.5.1","@types/node":"^20.2.3","@types/node-fetch":"^2.6.4","@typescript-eslint/eslint-plugin":"^7.18.0","@typescript-eslint/parser":"^7.18.0","eslint":"^8.57.0","express":"^4.18.2","fastify":"^5.1.0","jest":"^29.5.0","next":"^14.2.10","node-mocks-http":"^1.12.2","node-fetch":"^2.6.11","openapi-schema-validator":"^12.1.1","prettier":"^3.4.1","formatter-for-jest-snapshots":"npm:prettier@^2","rimraf":"^6.0.1","superjson":"^1.12.3","ts-jest":"^29.1.0","ts-node":"^10.9.1","typescript":"5.7.2"},"optionalDependencies":{"@rollup/rollup-linux-x64-gnu":"4.6.1"},"_id":"@dum3ng/trpc-to-openapi@2.1.1","gitHead":"51a13d551baddde03d220bb96837172f314fe8be","_nodeVersion":"20.12.2","_npmVersion":"10.5.0","dist":{"integrity":"sha512-xRllNY9VZ3zl9gd/9b5Nszj7ewxwr5kEPvx+zZdHlOlirARBA0FwGZi7foxmAZTfHeAXsEx8PtCD9do8/1JrIg==","shasum":"ae9971b3ca0758fac53ba35bb67a429428414420","tarball":"https://registry.npmjs.org/@dum3ng/trpc-to-openapi/-/trpc-to-openapi-2.1.1.tgz","fileCount":163,"unpackedSize":256487,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDmx1xJWRGocWTOeGJh7xVUvjNSnLtbflFGr7gFs8pWBwIhAIES7/kCxdbbEqIeYaU02Ml2a4+rGdY60lV02itkUccO"}]},"_npmUser":{"name":"dum3ng","email":"dumeng81@outlook.com"},"directories":{},"maintainers":[{"name":"dum3ng","email":"dumeng81@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/trpc-to-openapi_2.1.1_1735490451350_0.743331989808145"},"_hasShrinkwrap":false}},"time":{"created":"2024-12-29T16:40:51.235Z","2.1.1":"2024-12-29T16:40:51.549Z","modified":"2024-12-29T16:40:51.859Z"},"maintainers":[{"name":"dum3ng","email":"dumeng81@outlook.com"}],"description":"tRPC OpenAPI","homepage":"https://github.com/mcampa/trpc-to-openapi","keywords":["trpc","openapi","swagger"],"repository":{"type":"git","url":"git+https://github.com/mcampa/trpc-to-openapi.git"},"author":{"name":"mcampa"},"bugs":{"url":"https://github.com/mcampa/trpc-to-openapi/issues"},"license":"MIT","readme":"<p align=\"center\">\n  <img src=\"assets/trpc-openapi.svg\">\n</p>\n<div align=\"center\">\n  <h1>trpc-to-openapi</h1>\n  <a href=\"https://www.npmjs.com/package/trpc-to-openapi\"><img src=\"https://img.shields.io/npm/v/trpc-to-openapi.svg?style=flat&color=brightgreen\" target=\"_blank\" /></a>\n  <a href=\"./LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-black\" /></a>\n  <br />\n  <hr />\n</div>\n\n## **[OpenAPI](https://swagger.io/specification/) support for [tRPC](https://trpc.io/)** 🧩\n\n- tRPC ^11.0.0-rc.648 only 👈\n- Easy REST endpoints for your tRPC procedures.\n- Perfect for incremental adoption.\n- Supports all OpenAPI versions.\n\nNote: This project is a fork of a fork, with full credit to the original authors. It appears that the original author has abandoned the project, so I plan to add new features in the near future.\n\n## Usage\n\n**1. Install `trpc-to-openapi`.**\n\n```bash\n# npm\nnpm install trpc-to-openapi\n# yarn\nyarn add trpc-to-openapi\n```\n\n**2. Add `OpenApiMeta` to your tRPC instance.**\n\n```typescript\nimport { initTRPC } from '@trpc/server';\nimport { OpenApiMeta } from 'trpc-to-openapi';\n\nconst t = initTRPC.meta<OpenApiMeta>().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 }) => {\n      return { greeting: `Hello ${input.name}!` };\n    });\n});\n```\n\n**4. Generate an OpenAPI document.**\n\n```typescript\nimport { generateOpenApiDocument } from 'trpc-to-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-to-openapi` handler to your app.**\n\nWe currently support adapters for [`Express`](http://expressjs.com/), [`Next.js`](https://nextjs.org/), [`Fastify`](https://www.fastify.io/), [`Nuxt`](https://nuxtjs.org/) & [`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/) & more soon™, PRs are welcomed 🙌.\n\nNo support for AWS lambdas\n\n```typescript\nimport http from 'http';\nimport { createOpenApiHttpHandler } from 'trpc-to-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=Lily', { method: 'GET' });\nconst body = await res.json(); /* { greeting: 'Hello Lily!' } */\n```\n\n## Requirements\n\nPeer dependencies:\n\n- [`tRPC`](https://github.com/trpc/trpc) Server v11 (`@trpc/server`) must be installed.\n- [`Zod`](https://github.com/colinhacks/zod) v3 (`zod@^3.23.8`) must be installed.\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<{ [string]: String | Number | BigInt | Date }>` or `Void`.\n- Mutation `input` parsers extend `Object<{ [string]: AnyType }>` 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` 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 & 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 }) => {\n      return { greeting: `${input.greeting} ${input.name}!` };\n    });\n});\n\n// Client\nconst res = await fetch('http://localhost:3000/say-hello/Lily?greeting=Hello' /* 👈 */, {\n  method: 'GET',\n});\nconst body = await res.json(); /* { greeting: 'Hello Lily!' } */\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 }) => {\n      return { greeting: `${input.greeting} ${input.name}!` };\n    });\n});\n\n// Client\nconst res = await fetch('http://localhost:3000/say-hello/Lily' /* 👈 */, {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ greeting: 'Hello' }),\n});\nconst body = await res.json(); /* { greeting: 'Hello Lily!' } */\n```\n\n### Custom headers\n\nAny custom headers can be specified in the `meta.openapi.requestHeaders` and `meta.openapi.responseHeaders` zod object schema, these headers will not be validated. 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-to-openapi';\n\ntype User = { id: string; name: string };\n\nconst users: User[] = [\n  {\n    id: 'usr_123',\n    name: 'Lily',\n  },\n];\n\nexport type Context = { user: User | null };\n\nexport const createContext = async ({ req, res }): Promise<Context> => {\n  let user: User | null = null;\n  if (req.headers.authorization) {\n    const userId = req.headers.authorization.split(' ')[1];\n    user = users.find((_user) => _user.id === userId);\n  }\n  return { user };\n};\n\nconst t = initTRPC.context<Context>().meta<OpenApiMeta>().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 }) => {\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 Lily!' } */\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-to-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 app router\n\nPlease see [full example here](examples/with-nextjs-appdir).\n\n```typescript\n// src/app/[...trpc]/route.ts\nimport { appRouter } from '~/server/api/root';\nimport { createContext } from '~/server/api/trpc';\nimport { type NextRequest } from 'next/server';\nimport { createOpenApiFetchHandler } from 'trpc-to-openapi';\n\nexport const dynamic = 'force-dynamic';\n\nconst handler = (req: NextRequest) => {\n  // Handle incoming OpenAPI requests\n  return createOpenApiFetchHandler({\n    endpoint: '/',\n    router: appRouter,\n    createContext: () => createContext(req),\n    req,\n  });\n};\n\nexport {\n  handler as GET,\n  handler as POST,\n  handler as PUT,\n  handler as PATCH,\n  handler as DELETE,\n  handler as OPTIONS,\n  handler as HEAD,\n};\n```\n\n#### With Next.js pages router\n\nPlease see [full example here](examples/with-nextjs).\n\n```typescript\n// pages/api/[...trpc].ts\nimport { createOpenApiNextHandler } from 'trpc-to-openapi';\n\nimport { appRouter } from '../../server/appRouter';\n\nexport default createOpenApiNextHandler({ 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-to-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<string, SecuritySchemeObject>` | 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-to-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`  | `true`                  |\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| `requestHeaders`     | `AnyZodObject`                          | A zod object schema describing any custom headers to add to the request for this endpoint in the OpenAPI document.             | `false`  | `undefined`             |\n| `responseHeaders`    | `AnyZodObject`                          | A zod object schema describing any custom headers to add to the response for this endpoint in the OpenAPI document.            | `false`  | `undefined`             |\n| `successDescription` | `string`                                | A string to use as the description for a successful response.                                                                  | `false`  | `'Successful response'` |\n| `errorResponses`     | `number[] \\| { [key: number]: string }` | A list of error response codes or an object of response codes and their description to add to the responses for this endpoint. | `false`  | `undefined`             |\n| `contentTypes`       | `OpenApiContentType[]`                  | 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 & 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","readmeFilename":"README.md"}