@trpc/server
Version:
191 lines (144 loc) • 8.07 kB
Markdown
---
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 & 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 /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 '/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 '/server';
import * as trpcExpress from '/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 '/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 '/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`