UNPKG

@trpc/server

Version:

The tRPC server library

191 lines (144 loc) • 8.07 kB
--- name: adapter-express description: "Mount tRPC as Express middleware with createExpressMiddleware() from @trpc/server/adapters/express. Access Express req/res in createContext via CreateExpressContextOptions. Mount at a path prefix like app.use('/trpc', ...). Adapter options: onError, maxBatchSize, maxBodySize, middleware. Body parsers registered before tRPC (Express 4's express.json(), or express.raw()) break FormData and binary inputs, so scope them to non-tRPC routes." requires: - server-setup sources: - www/v11/docs/server/adapters/express.md - www/v11/docs/server/adapters.md metadata: type: core library: trpc library_version: 11.23.0 --- <!-- Generated from www/v11/docs/server/adapters/express.md by www/build/skills.ts. Edit the docs instead. --> # Express Adapter From https://trpc.io/docs/server/adapters/express ## Example app <table> <thead> <tr> <th>Description</th> <th>Links</th> </tr> </thead> <tbody> <tr> <td>Express server &amp; procedure calls with Node.js.</td> <td> <ul> <li><a href="https://githubbox.com/trpc/trpc/tree/main/examples/express-server">CodeSandbox</a></li> <li><a href="https://github.com/trpc/trpc/tree/main/examples/express-server">Source</a></li> </ul> </td> </tr> </tbody> </table> ## How to add tRPC to existing Express project ### 1. Install deps ```bash yarn add @trpc/server zod ``` > [Zod](https://github.com/colinhacks/zod) isn't a required dependency, but it's used in the sample router below. ### 2. Create a tRPC router Implement your tRPC router. A sample router is given below: ```ts no-check title="server.ts" import { initTRPC } from '@trpc/server'; import { z } from 'zod'; export const t = initTRPC.create(); export const appRouter = t.router({ getUser: t.procedure.input(z.string()).query((opts) => { opts.input; // string return { id: opts.input, name: 'Bilbo' }; }), createUser: t.procedure .input(z.object({ name: z.string().min(5) })) .mutation(async (opts) => { // use your ORM of choice return { id: '1', ...opts.input }; }), }); // export type definition of API export type AppRouter = typeof appRouter; ``` If your router file starts getting too big, split your router into several subrouters each implemented in its own file. Then [merge them](https://trpc.io/docs/server/merging-routers) into a single root `appRouter`. ### 3. Use the Express adapter tRPC includes an adapter for Express out of the box. This adapter lets you convert your tRPC router into an Express middleware. ```ts no-check title="server.ts" import { initTRPC } from '@trpc/server'; import * as trpcExpress from '@trpc/server/adapters/express'; import express from 'express'; // created for each request const createContext = ({ req, res, }: trpcExpress.CreateExpressContextOptions) => ({}); // no context type Context = Awaited<ReturnType<typeof createContext>>; const t = initTRPC.context<Context>().create(); const appRouter = t.router({ // [...] }); const app = express(); app.use( '/trpc', trpcExpress.createExpressMiddleware({ router: appRouter, createContext, }), ); app.listen(4000); ``` Your endpoints are now available via HTTP! | Endpoint | HTTP URI | | ------------ | ---------------------------------------------------------------------------------------------------------- | | `getUser` | `GET http://localhost:4000/trpc/getUser?input=INPUT` <br/><br/>where `INPUT` is a URI-encoded JSON string. | | `createUser` | `POST http://localhost:4000/trpc/createUser` <br/><br/>with `req.body` of type `{name: string}` | `createContext` receives Express's `req` and `res`, so you can, for example, read `req.headers.authorization` to [authorize the user](https://trpc.io/docs/server/authorization). The middleware accepts the [options every adapter takes](https://trpc.io/docs/server/adapters#common-options), like `onError` and `maxBatchSize`, plus `middleware` and `maxBodySize`. ## Body parsers tRPC parses request bodies itself, so tRPC routes don't need `express.json()`. If a body parser runs before tRPC anyway, tRPC uses the `req.body` it parsed, which works for JSON. For [FormData and binary inputs](https://trpc.io/docs/server/non-json-content-types) it depends on your Express version: - **Express 5**: `express.json()` and `express.urlencoded()` leave other content types unread, so tRPC still reads them. - **Express 4**: the parsers set `req.body` to `{}` on content types they skip, so tRPC receives `{}` instead of the form data or file. - In both versions, a parser that reads the body you upload, like `express.raw()` for `application/octet-stream`, breaks binary inputs. To be safe, register body parsers only on the routes that need them: ```ts no-check title="server.ts" import * as trpcExpress from '@trpc/server/adapters/express'; import express from 'express'; import { appRouter } from './router'; const app = express(); app.use('/api', express.json()); // only for your own `/api/*` routes app.post('/api/webhook', (req, res) => { res.json({ received: req.body }); }); app.use('/trpc', trpcExpress.createExpressMiddleware({ router: appRouter })); app.listen(4000); ``` ## Common options Every HTTP adapter accepts these options, next to its own (like `endpoint` for Fetch, or `basePath` for Standalone): | Option | Description | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `router` | Your app router. Required. | | `createContext` | Creates the [context](https://trpc.io/docs/server/context) for each request. It receives the adapter's own objects (e.g. `req` and `res`) plus `info`. | | `onError` | Called with `{ error, type, path, input, ctx, req }` for every error, e.g. to report it. See [Error handling](https://trpc.io/docs/server/error-handling#handling-errors). | | `responseMeta` | Returns `{ status, headers }` for the response, e.g. for [caching](https://trpc.io/docs/server/caching). | | `allowBatching` | Set to `false` to reject batch requests. Defaults to `true`. | | `maxBatchSize` | Rejects batch requests with more calls than this with a `400 Bad Request`. Set `maxItems` on your batch link to the same or a lower value. | | `allowMethodOverride` | Accepts queries sent as `POST`, for clients that set `methodOverride: 'POST'` on their link. Defaults to `false`. | The Node.js adapters (Standalone, Express and Next.js) also accept: - `maxBodySize`: the largest request body in bytes; larger ones are rejected with `413 PAYLOAD_TOO_LARGE`. - `middleware`: a connect-style `(req, res, next)` function that runs before tRPC, e.g. [`cors()`](https://trpc.io/docs/server/adapters/standalone#handling-cors--options). ```ts no-check title="server.ts" import { createHTTPServer } from '@trpc/server/adapters/standalone'; import { appRouter } from './router'; createHTTPServer({ router: appRouter, createContext: () => ({}), onError({ error, path }) { console.error(`tRPC error on '${path}':`, error); }, maxBatchSize: 10, maxBodySize: 1_000_000, // 1 MB }).listen(3000); ``` From https://trpc.io/docs/server/adapters#common-options ## Related skills - `server-setup` (https://trpc.io/docs/server/overview): `npx @tanstack/intent@latest load @trpc/server#server-setup`