@trpc/server 11.14.0 → 11.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/bin/intent.js +20 -0
- package/dist/adapters/next-app-dir.cjs +76 -76
- package/dist/adapters/next-app-dir.mjs +76 -76
- package/dist/adapters/next-app-dir.mjs.map +1 -1
- package/package.json +13 -3
- package/skills/adapter-aws-lambda/SKILL.md +188 -0
- package/skills/adapter-express/SKILL.md +152 -0
- package/skills/adapter-fastify/SKILL.md +206 -0
- package/skills/adapter-fetch/SKILL.md +177 -0
- package/skills/adapter-standalone/SKILL.md +184 -0
- package/skills/auth/SKILL.md +342 -0
- package/skills/caching/SKILL.md +205 -0
- package/skills/error-handling/SKILL.md +253 -0
- package/skills/middlewares/SKILL.md +242 -0
- package/skills/non-json-content-types/SKILL.md +265 -0
- package/skills/server-setup/SKILL.md +378 -0
- package/skills/server-side-calls/SKILL.md +249 -0
- package/skills/service-oriented-architecture/SKILL.md +247 -0
- package/skills/subscriptions/SKILL.md +406 -0
- package/skills/trpc-router/SKILL.md +151 -0
- package/skills/validators/SKILL.md +228 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: validators
|
|
3
|
+
description: >
|
|
4
|
+
Configure input and output validation with .input() and .output() using Zod,
|
|
5
|
+
Yup, Superstruct, ArkType, Valibot, Effect, or custom validator functions.
|
|
6
|
+
Chain multiple .input() calls to merge object schemas. Standard Schema protocol
|
|
7
|
+
support. Output validation returns INTERNAL_SERVER_ERROR on failure.
|
|
8
|
+
type: core
|
|
9
|
+
library: trpc
|
|
10
|
+
library_version: '11.14.0'
|
|
11
|
+
requires:
|
|
12
|
+
- server-setup
|
|
13
|
+
sources:
|
|
14
|
+
- 'trpc/trpc:www/docs/server/validators.md'
|
|
15
|
+
- 'trpc/trpc:packages/server/src/unstable-core-do-not-import/parser.ts'
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# tRPC -- Validators
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// server/trpc.ts
|
|
24
|
+
import { initTRPC } from '@trpc/server';
|
|
25
|
+
|
|
26
|
+
const t = initTRPC.create();
|
|
27
|
+
|
|
28
|
+
export const router = t.router;
|
|
29
|
+
export const publicProcedure = t.procedure;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// server/appRouter.ts
|
|
34
|
+
import { z } from 'zod';
|
|
35
|
+
import { publicProcedure, router } from './trpc';
|
|
36
|
+
|
|
37
|
+
export const appRouter = router({
|
|
38
|
+
hello: publicProcedure
|
|
39
|
+
.input(z.object({ name: z.string() }))
|
|
40
|
+
.output(z.object({ greeting: z.string() }))
|
|
41
|
+
.query(({ input }) => {
|
|
42
|
+
return { greeting: `hello ${input.name}` };
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export type AppRouter = typeof appRouter;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Core Patterns
|
|
50
|
+
|
|
51
|
+
### Input validation with Zod
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { z } from 'zod';
|
|
55
|
+
import { publicProcedure, router } from './trpc';
|
|
56
|
+
|
|
57
|
+
export const appRouter = router({
|
|
58
|
+
userById: publicProcedure.input(z.string()).query(({ input }) => {
|
|
59
|
+
return { id: input, name: 'Katt' };
|
|
60
|
+
}),
|
|
61
|
+
userCreate: publicProcedure
|
|
62
|
+
.input(z.object({ name: z.string(), email: z.string().email() }))
|
|
63
|
+
.mutation(({ input }) => {
|
|
64
|
+
return { id: '1', ...input };
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Input chaining to merge object schemas
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { initTRPC } from '@trpc/server';
|
|
73
|
+
import { z } from 'zod';
|
|
74
|
+
|
|
75
|
+
const t = initTRPC.create();
|
|
76
|
+
|
|
77
|
+
const baseProcedure = t.procedure
|
|
78
|
+
.input(z.object({ townName: z.string() }))
|
|
79
|
+
.use((opts) => {
|
|
80
|
+
console.log(`Request from: ${opts.input.townName}`);
|
|
81
|
+
return opts.next();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export const appRouter = t.router({
|
|
85
|
+
hello: baseProcedure
|
|
86
|
+
.input(z.object({ name: z.string() }))
|
|
87
|
+
.query(({ input }) => {
|
|
88
|
+
return { greeting: `Hello ${input.name}, from ${input.townName}` };
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Multiple `.input()` calls merge object properties; the final input type is `{ townName: string; name: string }`.
|
|
94
|
+
|
|
95
|
+
### Output validation
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { z } from 'zod';
|
|
99
|
+
import { publicProcedure, router } from './trpc';
|
|
100
|
+
|
|
101
|
+
export const appRouter = router({
|
|
102
|
+
hello: publicProcedure
|
|
103
|
+
.output(z.object({ greeting: z.string() }))
|
|
104
|
+
.query(() => {
|
|
105
|
+
return { greeting: 'hello world' };
|
|
106
|
+
}),
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Output validation catches mismatches between your return type and the expected shape, useful for untrusted data sources.
|
|
111
|
+
|
|
112
|
+
### Custom validator function (no library)
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { initTRPC } from '@trpc/server';
|
|
116
|
+
|
|
117
|
+
const t = initTRPC.create();
|
|
118
|
+
|
|
119
|
+
export const appRouter = t.router({
|
|
120
|
+
hello: t.procedure
|
|
121
|
+
.input((value): string => {
|
|
122
|
+
if (typeof value === 'string') return value;
|
|
123
|
+
throw new Error('Input is not a string');
|
|
124
|
+
})
|
|
125
|
+
.output((value): string => {
|
|
126
|
+
if (typeof value === 'string') return value;
|
|
127
|
+
throw new Error('Output is not a string');
|
|
128
|
+
})
|
|
129
|
+
.query(({ input }) => {
|
|
130
|
+
return `hello ${input}`;
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Common Mistakes
|
|
136
|
+
|
|
137
|
+
### [MEDIUM] Chaining non-object inputs
|
|
138
|
+
|
|
139
|
+
Wrong:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { z } from 'zod';
|
|
143
|
+
import { publicProcedure } from './trpc';
|
|
144
|
+
|
|
145
|
+
const proc = publicProcedure.input(z.string()).input(z.number());
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Correct:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { z } from 'zod';
|
|
152
|
+
import { publicProcedure } from './trpc';
|
|
153
|
+
|
|
154
|
+
const proc = publicProcedure
|
|
155
|
+
.input(z.object({ name: z.string() }))
|
|
156
|
+
.input(z.object({ age: z.number() }));
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Multiple `.input()` calls merge object properties; non-object schemas (string, number, array) cannot be merged and produce type errors.
|
|
160
|
+
|
|
161
|
+
Source: www/docs/server/validators.md
|
|
162
|
+
|
|
163
|
+
### [MEDIUM] Output validation failure returns 500
|
|
164
|
+
|
|
165
|
+
Wrong:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { z } from 'zod';
|
|
169
|
+
import { publicProcedure } from './trpc';
|
|
170
|
+
|
|
171
|
+
const proc = publicProcedure
|
|
172
|
+
.output(z.object({ id: z.string() }))
|
|
173
|
+
.query(() => ({ id: 123 }));
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Correct:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { z } from 'zod';
|
|
180
|
+
import { publicProcedure } from './trpc';
|
|
181
|
+
|
|
182
|
+
const proc = publicProcedure
|
|
183
|
+
.output(z.object({ id: z.string() }))
|
|
184
|
+
.query(() => ({ id: '123' }));
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
If `.output()` validation fails, tRPC returns INTERNAL_SERVER_ERROR (500), not BAD_REQUEST, because the server produced invalid data.
|
|
188
|
+
|
|
189
|
+
Source: www/docs/server/validators.md
|
|
190
|
+
|
|
191
|
+
### [HIGH] Using cursor: z.optional() without nullable for infinite queries
|
|
192
|
+
|
|
193
|
+
Wrong:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import { z } from 'zod';
|
|
197
|
+
import { publicProcedure } from './trpc';
|
|
198
|
+
|
|
199
|
+
const proc = publicProcedure
|
|
200
|
+
.input(z.object({ cursor: z.string().optional() }))
|
|
201
|
+
.query(({ input }) => {
|
|
202
|
+
return { items: [], nextCursor: input.cursor };
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Correct:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
import { z } from 'zod';
|
|
210
|
+
import { publicProcedure } from './trpc';
|
|
211
|
+
|
|
212
|
+
const proc = publicProcedure
|
|
213
|
+
.input(z.object({ cursor: z.string().nullish() }))
|
|
214
|
+
.query(({ input }) => {
|
|
215
|
+
return { items: [], nextCursor: input.cursor };
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
React Query internally passes `cursor: undefined` during invalidation refetch; using `.optional()` without `.nullable()` can fail validation. Use `.nullish()` instead.
|
|
220
|
+
|
|
221
|
+
Source: https://github.com/trpc/trpc/issues/6862
|
|
222
|
+
|
|
223
|
+
## See Also
|
|
224
|
+
|
|
225
|
+
- `server-setup` -- initTRPC, routers, procedures
|
|
226
|
+
- `error-handling` -- how validation errors surface as BAD_REQUEST
|
|
227
|
+
- `error-handling` -- errorFormatter to expose Zod field errors
|
|
228
|
+
- `middlewares` -- use input chaining with middleware base procedures
|