UEA-Prodem
This commit is contained in:
+176
@@ -0,0 +1,176 @@
|
||||
---
|
||||
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', ...).
|
||||
Avoid global express.json() conflicting with tRPC body parsing for FormData.
|
||||
type: core
|
||||
library: trpc
|
||||
library_version: '11.16.0'
|
||||
requires:
|
||||
- server-setup
|
||||
sources:
|
||||
- www/docs/server/adapters/express.md
|
||||
- examples/express-server/src/server.ts
|
||||
---
|
||||
|
||||
# tRPC — Adapter: Express
|
||||
|
||||
## Setup
|
||||
|
||||
```ts
|
||||
// server.ts
|
||||
import { initTRPC } from '@trpc/server';
|
||||
import * as trpcExpress from '@trpc/server/adapters/express';
|
||||
import express from 'express';
|
||||
import { z } from 'zod';
|
||||
|
||||
const createContext = ({
|
||||
req,
|
||||
res,
|
||||
}: trpcExpress.CreateExpressContextOptions) => {
|
||||
return { req, res };
|
||||
};
|
||||
type Context = Awaited<ReturnType<typeof createContext>>;
|
||||
|
||||
const t = initTRPC.context<Context>().create();
|
||||
|
||||
const appRouter = t.router({
|
||||
greet: t.procedure
|
||||
.input(z.object({ name: z.string() }))
|
||||
.query(({ input }) => ({ greeting: `Hello, ${input.name}!` })),
|
||||
});
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(
|
||||
'/trpc',
|
||||
trpcExpress.createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
}),
|
||||
);
|
||||
|
||||
app.listen(4000, () => {
|
||||
console.log('Listening on http://localhost:4000');
|
||||
});
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Accessing Express req/res in context
|
||||
|
||||
```ts
|
||||
import * as trpcExpress from '@trpc/server/adapters/express';
|
||||
|
||||
const createContext = ({
|
||||
req,
|
||||
res,
|
||||
}: trpcExpress.CreateExpressContextOptions) => {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
return { token, res };
|
||||
};
|
||||
|
||||
type Context = Awaited<ReturnType<typeof createContext>>;
|
||||
```
|
||||
|
||||
`CreateExpressContextOptions` provides typed access to the Express `req` (IncomingMessage) and `res` (ServerResponse).
|
||||
|
||||
### Adding tRPC alongside existing Express routes
|
||||
|
||||
```ts
|
||||
import * as trpcExpress from '@trpc/server/adapters/express';
|
||||
import cors from 'cors';
|
||||
import express from 'express';
|
||||
import { createContext } from './context';
|
||||
import { appRouter } from './router';
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cors());
|
||||
|
||||
app.get('/health', (_req, res) => {
|
||||
res.json({ status: 'ok' });
|
||||
});
|
||||
|
||||
app.use(
|
||||
'/trpc',
|
||||
trpcExpress.createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
}),
|
||||
);
|
||||
|
||||
app.listen(4000);
|
||||
```
|
||||
|
||||
### Limiting batch size with maxBatchSize
|
||||
|
||||
```ts
|
||||
import * as trpcExpress from '@trpc/server/adapters/express';
|
||||
import express from 'express';
|
||||
import { createContext } from './context';
|
||||
import { appRouter } from './router';
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(
|
||||
'/trpc',
|
||||
trpcExpress.createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
maxBatchSize: 10,
|
||||
}),
|
||||
);
|
||||
|
||||
app.listen(4000);
|
||||
```
|
||||
|
||||
Requests batching more than `maxBatchSize` operations are rejected with a `400 Bad Request` error. Set `maxItems` on your client's `httpBatchLink` to the same value to avoid exceeding the limit.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### HIGH Global express.json() consuming tRPC request body
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const app = express();
|
||||
app.use(express.json()); // global body parser
|
||||
app.use(
|
||||
'/trpc',
|
||||
trpcExpress.createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
const app = express();
|
||||
// Only apply body parser to non-tRPC routes
|
||||
app.use('/api', express.json());
|
||||
app.use(
|
||||
'/trpc',
|
||||
trpcExpress.createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
If `express.json()` is applied globally before the tRPC middleware, it consumes and parses the request body. tRPC then receives an already-parsed body, which breaks FormData and binary content type handling.
|
||||
|
||||
Source: www/docs/server/non-json-content-types.md
|
||||
|
||||
## See Also
|
||||
|
||||
- **server-setup** -- `initTRPC.create()`, router/procedure definition, context
|
||||
- **adapter-standalone** -- simpler adapter when Express middleware ecosystem is not needed
|
||||
- **auth** -- extracting JWT from `req.headers.authorization` in context
|
||||
- Express docs: https://expressjs.com/en/guide/using-middleware.html
|
||||
Reference in New Issue
Block a user