express-zod-api 25.5.3 → 26.0.0-beta.2
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/CHANGELOG.md +43 -0
- package/README.md +88 -98
- package/dist/index.d.ts +112 -105
- package/dist/index.js +6 -6
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Version 26
|
|
4
|
+
|
|
5
|
+
### v26.0.0
|
|
6
|
+
|
|
7
|
+
- Supported `zod` versions: `^4.1.13`:
|
|
8
|
+
- This Zod patch contains an [important fix](https://github.com/colinhacks/zod/pull/5452) that makes the
|
|
9
|
+
`globalRegistry` really global across both CJS and ESM bundles of Zod distribution;
|
|
10
|
+
- The issue was found and reported by [@shadone](https://github.com/shadone);
|
|
11
|
+
- New version of Zod plugin now also extends the CJS exports of Zod:
|
|
12
|
+
- This fixes the "TypeError: example is not a function" in CJS and removes the requirement to use ESM environment;
|
|
13
|
+
- The issue reported by [@squishykid](https://github.com/squishykid), and addressed earlier in [v25.5.3](#v2553);
|
|
14
|
+
- `DependsOnMethod` removed:
|
|
15
|
+
- You can now specify methods as direct keys of an assigned object in `Routing`;
|
|
16
|
+
- That object can still contain nested paths as before;
|
|
17
|
+
- The keys matching lowercase HTTP methods are treated according to the new config setting `methodLikeRouteBehavior`:
|
|
18
|
+
- `method` — when assigned with an Endpoint the key is treated as method of its parent path (default);
|
|
19
|
+
- `path` — the key is always treated as a nested path segment;
|
|
20
|
+
- `options` property renamed to `ctx` in argument of:
|
|
21
|
+
- `Middleware::handler()`,
|
|
22
|
+
- `ResultHandler::handler()`,
|
|
23
|
+
- `handler` of `EndpointsFactory::build()` argument,
|
|
24
|
+
- `testMiddleware()`;
|
|
25
|
+
- `EndpointsFactory::addOptions()` renamed to `addContext()`;
|
|
26
|
+
- The `Integration::constructor()` argument object now requires `config` property, similar to `Documentation`;
|
|
27
|
+
|
|
28
|
+
```patch
|
|
29
|
+
const routing: Routing = {
|
|
30
|
+
- "/v1/users": new DependsOnMethod({
|
|
31
|
+
+ "/v1/users": {
|
|
32
|
+
get: getUserEndpoint,
|
|
33
|
+
- }).nest({
|
|
34
|
+
create: makeUserEndpoint
|
|
35
|
+
- }),
|
|
36
|
+
+ },
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
3
40
|
## Version 25
|
|
4
41
|
|
|
42
|
+
### v25.6.0
|
|
43
|
+
|
|
44
|
+
- Added `afterRouting` hook to server configuration:
|
|
45
|
+
- Similar to `beforeRouting` one;
|
|
46
|
+
- A code to execute after processing the Routing of your API, but before error handling.
|
|
47
|
+
|
|
5
48
|
### v25.5.3
|
|
6
49
|
|
|
7
50
|
- Updated environment requirements in the Readme:
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Start your API server with I/O schema validation and custom middlewares in minut
|
|
|
19
19
|
4. [Basic features](#basic-features)
|
|
20
20
|
1. [Routing](#routing) including static file serving
|
|
21
21
|
2. [Middlewares](#middlewares)
|
|
22
|
-
3. [
|
|
22
|
+
3. [Context](#context)
|
|
23
23
|
4. [Using native express middlewares](#using-native-express-middlewares)
|
|
24
24
|
5. [Refinements](#refinements)
|
|
25
25
|
6. [Query string parser](#query-string-parser)
|
|
@@ -86,61 +86,62 @@ Therefore, many basic tasks can be accomplished faster and easier, in particular
|
|
|
86
86
|
|
|
87
87
|
These people contributed to the improvement of the framework by reporting bugs, making changes and suggesting ideas:
|
|
88
88
|
|
|
89
|
-
[<img src="https://github.com/
|
|
90
|
-
[<img src="https://github.com/
|
|
91
|
-
[<img src="https://github.com/
|
|
92
|
-
[<img src="https://github.com/
|
|
93
|
-
[<img src="https://github.com/
|
|
94
|
-
[<img src="https://github.com/
|
|
95
|
-
[<img src="https://github.com/
|
|
96
|
-
[<img src="https://github.com/
|
|
97
|
-
[<img src="https://github.com/
|
|
98
|
-
[<img src="https://github.com/
|
|
99
|
-
[<img src="https://github.com/
|
|
100
|
-
[<img src="https://github.com/
|
|
101
|
-
[<img src="https://github.com/
|
|
102
|
-
[<img src="https://github.com/
|
|
103
|
-
[<img src="https://github.com/
|
|
104
|
-
[<img src="https://github.com/
|
|
105
|
-
[<img src="https://github.com/
|
|
106
|
-
[<img src="https://github.com/
|
|
107
|
-
[<img src="https://github.com/
|
|
108
|
-
[<img src="https://github.com/
|
|
109
|
-
[<img src="https://github.com/
|
|
110
|
-
[<img src="https://github.com/
|
|
111
|
-
[<img src="https://github.com/
|
|
112
|
-
[<img src="https://github.com/
|
|
113
|
-
[<img src="https://github.com/
|
|
114
|
-
[<img src="https://github.com/
|
|
115
|
-
[<img src="https://github.com/
|
|
116
|
-
[<img src="https://github.com/
|
|
117
|
-
[<img src="https://github.com/
|
|
118
|
-
[<img src="https://github.com/
|
|
119
|
-
[<img src="https://github.com/
|
|
120
|
-
[<img src="https://github.com/
|
|
121
|
-
[<img src="https://github.com/
|
|
122
|
-
[<img src="https://github.com/
|
|
123
|
-
[<img src="https://github.com/
|
|
124
|
-
[<img src="https://github.com/
|
|
125
|
-
[<img src="https://github.com/
|
|
126
|
-
[<img src="https://github.com/
|
|
127
|
-
[<img src="https://github.com/
|
|
128
|
-
[<img src="https://github.com/
|
|
129
|
-
[<img src="https://github.com/
|
|
130
|
-
[<img src="https://github.com/
|
|
131
|
-
[<img src="https://github.com/
|
|
132
|
-
[<img src="https://github.com/
|
|
133
|
-
[<img src="https://github.com/
|
|
134
|
-
[<img src="https://github.com/
|
|
135
|
-
[<img src="https://github.com/
|
|
136
|
-
[<img src="https://github.com/
|
|
137
|
-
[<img src="https://github.com/
|
|
138
|
-
[<img src="https://github.com/
|
|
139
|
-
[<img src="https://github.com/
|
|
140
|
-
[<img src="https://github.com/
|
|
141
|
-
[<img src="https://github.com/
|
|
142
|
-
[<img src="https://github.com/
|
|
143
|
-
[<img src="https://github.com/
|
|
89
|
+
[<img src="https://github.com/shadone.png" alt="@shadone" width="50" />](https://github.com/shadone)
|
|
90
|
+
[<img src="https://github.com/squishykid.png" alt="@squishykid" width="50" />](https://github.com/squishykid)
|
|
91
|
+
[<img src="https://github.com/jakub-msqt.png" alt="@jakub-msqt" width="50" />](https://github.com/jakub-msqt)
|
|
92
|
+
[<img src="https://github.com/misha-z1nchuk.png" alt="@misha-z1nchuk" width="50" />](https://github.com/misha-z1nchuk)
|
|
93
|
+
[<img src="https://github.com/GreaterTamarack.png" alt="@GreaterTamarack" width="50" />](https://github.com/GreaterTamarack)
|
|
94
|
+
[<img src="https://github.com/pepegc.png" alt="@pepegc" width="50" />](https://github.com/pepegc)
|
|
95
|
+
[<img src="https://github.com/MichaelHindley.png" alt="@MichaelHindley" width="50" />](https://github.com/MichaelHindley)
|
|
96
|
+
[<img src="https://github.com/zoton2.png" alt="@zoton2" width="50" />](https://github.com/zoton2)
|
|
97
|
+
[<img src="https://github.com/ThomasKientz.png" alt="@ThomasKientz" width="50" />](https://github.com/ThomasKientz)
|
|
98
|
+
[<img src="https://github.com/james10424.png" alt="@james10424" width="50" />](https://github.com/james10424)
|
|
99
|
+
[<img src="https://github.com/HeikoOsigus.png" alt="@HeikoOsigus" width="50" />](https://github.com/HeikoOsigus)
|
|
100
|
+
[<img src="https://github.com/crgeary.png" alt="@crgeary" width="50" />](https://github.com/crgeary)
|
|
101
|
+
[<img src="https://github.com/williamgcampbell.png" alt="@williamgcampbell" width="50" />](https://github.com/williamgcampbell)
|
|
102
|
+
[<img src="https://github.com/gmorgen1.png" alt="@gmorgen1" width="50" />](https://github.com/gmorgen1)
|
|
103
|
+
[<img src="https://github.com/danmichaelo.png" alt="@danmichaelo" width="50" />](https://github.com/danmichaelo)
|
|
104
|
+
[<img src="https://github.com/APTy.png" alt="@APTy" width="50" />](https://github.com/APTy)
|
|
105
|
+
[<img src="https://github.com/LufyCZ.png" alt="@LufyCZ" width="50" />](https://github.com/LufyCZ)
|
|
106
|
+
[<img src="https://github.com/mlms13.png" alt="@mlms13" width="50" />](https://github.com/mlms13)
|
|
107
|
+
[<img src="https://github.com/bobgubko.png" alt="@bobgubko" width="50" />](https://github.com/bobgubko)
|
|
108
|
+
[<img src="https://github.com/LucWag.png" alt="@LucWag" width="50" />](https://github.com/LucWag)
|
|
109
|
+
[<img src="https://github.com/HenriJ.png" alt="@HenriJ" width="50" />](https://github.com/HenriJ)
|
|
110
|
+
[<img src="https://github.com/JonParton.png" alt="@JonParton" width="50" />](https://github.com/JonParton)
|
|
111
|
+
[<img src="https://github.com/t1nky.png" alt="@t1nky" width="50" />](https://github.com/t1nky)
|
|
112
|
+
[<img src="https://github.com/Tomtec331.png" alt="@Tomtec331" width="50" />](https://github.com/Tomtec331)
|
|
113
|
+
[<img src="https://github.com/rottmann.png" alt="@rottmann" width="50" />](https://github.com/rottmann)
|
|
114
|
+
[<img src="https://github.com/boarush.png" alt="@boarush" width="50" />](https://github.com/boarush)
|
|
115
|
+
[<img src="https://github.com/shawncarr.png" alt="@shawncarr" width="50" />](https://github.com/shawncarr)
|
|
116
|
+
[<img src="https://github.com/ben-xD.png" alt="@ben-xD" width="50" />](https://github.com/ben-xD)
|
|
117
|
+
[<img src="https://github.com/daniel-white.png" alt="@daniel-white" width="50" />](https://github.com/daniel-white)
|
|
118
|
+
[<img src="https://github.com/kotsmile.png" alt="@kotsmile" width="50" />](https://github.com/kotsmile)
|
|
119
|
+
[<img src="https://github.com/arlyon.png" alt="@arlyon" width="50" />](https://github.com/arlyon)
|
|
120
|
+
[<img src="https://github.com/elee1766.png" alt="@elee1766" width="50" />](https://github.com/elee1766)
|
|
121
|
+
[<img src="https://github.com/danclaytondev.png" alt="@danclaytondev" width="50" />](https://github.com/danclaytondev)
|
|
122
|
+
[<img src="https://github.com/huyhoang160593.png" alt="@huyhoang160593" width="50" />](https://github.com/huyhoang160593)
|
|
123
|
+
[<img src="https://github.com/sarahssharkey.png" alt="@sarahssharkey" width="50" />](https://github.com/sarahssharkey)
|
|
124
|
+
[<img src="https://github.com/master-chu.png" alt="@master-chu" width="50" />](https://github.com/master-chu)
|
|
125
|
+
[<img src="https://github.com/alindsay55661.png" alt="@alindsay55661" width="50" />](https://github.com/alindsay55661)
|
|
126
|
+
[<img src="https://github.com/john-schmitz.png" alt="@john-schmitz" width="50" />](https://github.com/john-schmitz)
|
|
127
|
+
[<img src="https://github.com/miki725.png" alt="@miki725" width="50" />](https://github.com/miki725)
|
|
128
|
+
[<img src="https://github.com/dev-m1-macbook.png" alt="@dev-m1-macbook" width="50" />](https://github.com/dev-m1-macbook)
|
|
129
|
+
[<img src="https://github.com/McMerph.png" alt="@McMerph" width="50" />](https://github.com/McMerph)
|
|
130
|
+
[<img src="https://github.com/niklashigi.png" alt="@niklashigi" width="50" />](https://github.com/niklashigi)
|
|
131
|
+
[<img src="https://github.com/maxcohn.png" alt="@maxcohn" width="50" />](https://github.com/maxcohn)
|
|
132
|
+
[<img src="https://github.com/VideoSystemsTech.png" alt="@VideoSystemsTech" width="50" />](https://github.com/VideoSystemsTech)
|
|
133
|
+
[<img src="https://github.com/TheWisestOne.png" alt="@TheWisestOne" width="50" />](https://github.com/TheWisestOne)
|
|
134
|
+
[<img src="https://github.com/lazylace37.png" alt="@lazylace37" width="50" />](https://github.com/lazylace37)
|
|
135
|
+
[<img src="https://github.com/leosuncin.png" alt="@leosuncin" width="50" />](https://github.com/leosuncin)
|
|
136
|
+
[<img src="https://github.com/kirdk.png" alt="@kirdk" width="50" />](https://github.com/kirdk)
|
|
137
|
+
[<img src="https://github.com/johngeorgewright.png" alt="@johngeorgewright" width="50" />](https://github.com/johngeorgewright)
|
|
138
|
+
[<img src="https://github.com/ssteuteville.png" alt="@ssteuteville" width="50" />](https://github.com/ssteuteville)
|
|
139
|
+
[<img src="https://github.com/foxfirecodes.png" alt="@foxfirecodes" width="50" />](https://github.com/foxfirecodes)
|
|
140
|
+
[<img src="https://github.com/HardCoreQual.png" alt="@HardCoreQual" width="50" />](https://github.com/HardCoreQual)
|
|
141
|
+
[<img src="https://github.com/hellovai.png" alt="@hellovai" width="50" />](https://github.com/hellovai)
|
|
142
|
+
[<img src="https://github.com/Isaac-Leonard.png" alt="@Isaac-Leonard" width="50" />](https://github.com/Isaac-Leonard)
|
|
143
|
+
[<img src="https://github.com/digimuza.png" alt="@digimuza" width="50" />](https://github.com/digimuza)
|
|
144
|
+
[<img src="https://github.com/glitch452.png" alt="@glitch452" width="50" />](https://github.com/glitch452)
|
|
144
145
|
|
|
145
146
|
# How it works
|
|
146
147
|
|
|
@@ -149,7 +150,7 @@ These people contributed to the improvement of the framework by reporting bugs,
|
|
|
149
150
|
The API operates object schemas for input and output validation.
|
|
150
151
|
The object being validated is the combination of certain `request` properties.
|
|
151
152
|
It is available to the endpoint handler as the `input` parameter.
|
|
152
|
-
Middlewares have access to all `request` properties, they can provide endpoints with `
|
|
153
|
+
Middlewares have access to all `request` properties, they can provide endpoints with `ctx` (context).
|
|
153
154
|
The object returned by the endpoint handler is called `output`. It goes to the `ResultHandler` which is
|
|
154
155
|
responsible for transmitting consistent responses containing the `output` or possible error.
|
|
155
156
|
Much can be customized to fit your needs.
|
|
@@ -185,12 +186,6 @@ pnpm add -D @types/express @types/node @types/http-errors
|
|
|
185
186
|
|
|
186
187
|
## Environment preparation
|
|
187
188
|
|
|
188
|
-
Ensure running your code as [ESM](https://nodejs.org/api/esm.html#enabling) by either:
|
|
189
|
-
|
|
190
|
-
- setting `"type": "module"` in your `package.json`;
|
|
191
|
-
- or using `.mts` file extension;
|
|
192
|
-
- or using `tsx` or `vite-node` or similar tools.
|
|
193
|
-
|
|
194
189
|
Enable the following `compilerOptions` in your `tsconfig.json` to make it work as expected:
|
|
195
190
|
|
|
196
191
|
```json
|
|
@@ -233,8 +228,8 @@ const helloWorldEndpoint = defaultEndpointsFactory.build({
|
|
|
233
228
|
output: z.object({
|
|
234
229
|
greetings: z.string(),
|
|
235
230
|
}),
|
|
236
|
-
handler: async ({ input: { name },
|
|
237
|
-
logger.debug("
|
|
231
|
+
handler: async ({ input: { name }, ctx, logger }) => {
|
|
232
|
+
logger.debug("Context:", ctx); // middlewares provide ctx
|
|
238
233
|
return { greetings: `Hello, ${name || "World"}. Happy coding!` };
|
|
239
234
|
},
|
|
240
235
|
});
|
|
@@ -288,7 +283,7 @@ in one place, illustrating how you can structure your API using whichever method
|
|
|
288
283
|
architecture — or even mix them seamlessly.
|
|
289
284
|
|
|
290
285
|
```ts
|
|
291
|
-
import { Routing,
|
|
286
|
+
import { Routing, ServeStatic } from "express-zod-api";
|
|
292
287
|
|
|
293
288
|
const routing: Routing = {
|
|
294
289
|
// flat syntax — /v1/users
|
|
@@ -306,12 +301,12 @@ const routing: Routing = {
|
|
|
306
301
|
// mixed syntax with explicit method — /v1/user/:id
|
|
307
302
|
"delete /user/:id": deleteUserEndpoint,
|
|
308
303
|
// method-based routing — /v1/account
|
|
309
|
-
account:
|
|
304
|
+
account: {
|
|
310
305
|
get: endpointA,
|
|
311
306
|
delete: endpointA,
|
|
312
307
|
post: endpointB,
|
|
313
308
|
patch: endpointB,
|
|
314
|
-
}
|
|
309
|
+
},
|
|
315
310
|
},
|
|
316
311
|
// static file serving — /public serves files from ./assets
|
|
317
312
|
public: new ServeStatic("assets", {
|
|
@@ -329,7 +324,7 @@ When the method is not specified, the one(s) supported by the Endpoint applied (
|
|
|
329
324
|
|
|
330
325
|
## Middlewares
|
|
331
326
|
|
|
332
|
-
Middleware can authenticate using input or `request` headers, and can provide endpoint handlers with `
|
|
327
|
+
Middleware can authenticate using input or `request` headers, and can provide endpoint handlers with `ctx`.
|
|
333
328
|
Inputs of middlewares are also available to endpoint handlers within `input`.
|
|
334
329
|
|
|
335
330
|
Here is an example of the authentication middleware, that checks a `key` from input and `token` from headers:
|
|
@@ -356,7 +351,7 @@ const authMiddleware = new Middleware({
|
|
|
356
351
|
if (!user) throw createHttpError(401, "Invalid key");
|
|
357
352
|
if (request.headers.token !== user.token)
|
|
358
353
|
throw createHttpError(401, "Invalid token");
|
|
359
|
-
return { user }; // provides endpoints with
|
|
354
|
+
return { user }; // provides endpoints with ctx.user
|
|
360
355
|
},
|
|
361
356
|
});
|
|
362
357
|
```
|
|
@@ -367,7 +362,7 @@ By using `.addMiddleware()` method before `.build()` you can connect it to the e
|
|
|
367
362
|
const yourEndpoint = defaultEndpointsFactory
|
|
368
363
|
.addMiddleware(authMiddleware)
|
|
369
364
|
.build({
|
|
370
|
-
handler: async ({
|
|
365
|
+
handler: async ({ ctx: { user } }) => {
|
|
371
366
|
// user is the one returned by authMiddleware
|
|
372
367
|
}, // ...
|
|
373
368
|
});
|
|
@@ -375,7 +370,7 @@ const yourEndpoint = defaultEndpointsFactory
|
|
|
375
370
|
|
|
376
371
|
You can create a new factory by connecting as many middlewares as you want — they will be executed in the specified
|
|
377
372
|
order for all the endpoints produced on that factory. You may also use a shorter inline syntax within the
|
|
378
|
-
`.addMiddleware()` method, and have access to the output of the previously executed middlewares in chain as `
|
|
373
|
+
`.addMiddleware()` method, and have access to the output of the previously executed middlewares in chain as `ctx`:
|
|
379
374
|
|
|
380
375
|
```ts
|
|
381
376
|
import { defaultEndpointsFactory } from "express-zod-api";
|
|
@@ -383,20 +378,20 @@ import { defaultEndpointsFactory } from "express-zod-api";
|
|
|
383
378
|
const factory = defaultEndpointsFactory
|
|
384
379
|
.addMiddleware(authMiddleware) // add Middleware instance or use shorter syntax:
|
|
385
380
|
.addMiddleware({
|
|
386
|
-
handler: async ({
|
|
381
|
+
handler: async ({ ctx: { user } }) => ({}), // user from authMiddleware
|
|
387
382
|
});
|
|
388
383
|
```
|
|
389
384
|
|
|
390
|
-
##
|
|
385
|
+
## Context
|
|
391
386
|
|
|
392
|
-
|
|
393
|
-
|
|
387
|
+
If you need to provide your endpoints with a context that does not depend on Request, like non-persistent database
|
|
388
|
+
connection, consider shorthand method `addContext`. For static values consider reusing a `const` across your files.
|
|
394
389
|
|
|
395
390
|
```ts
|
|
396
391
|
import { readFile } from "node:fs/promises";
|
|
397
392
|
import { defaultEndpointsFactory } from "express-zod-api";
|
|
398
393
|
|
|
399
|
-
const endpointsFactory = defaultEndpointsFactory.
|
|
394
|
+
const endpointsFactory = defaultEndpointsFactory.addContext(async () => {
|
|
400
395
|
// caution: new connection on every request:
|
|
401
396
|
const db = mongoose.connect("mongodb://connection.string");
|
|
402
397
|
const privateKey = await readFile("private-key.pem", "utf-8");
|
|
@@ -411,10 +406,10 @@ custom [Result Handler](#response-customization):
|
|
|
411
406
|
import { ResultHandler } from "express-zod-api";
|
|
412
407
|
|
|
413
408
|
const resultHandlerWithCleanup = new ResultHandler({
|
|
414
|
-
handler: ({
|
|
415
|
-
// necessary to check
|
|
416
|
-
if ("db" in
|
|
417
|
-
|
|
409
|
+
handler: ({ ctx }) => {
|
|
410
|
+
// necessary to check the presence of a certain property:
|
|
411
|
+
if ("db" in ctx && ctx.db) {
|
|
412
|
+
ctx.db.connection.close(); // sample cleanup
|
|
418
413
|
}
|
|
419
414
|
},
|
|
420
415
|
});
|
|
@@ -446,7 +441,7 @@ const config = createConfig({
|
|
|
446
441
|
|
|
447
442
|
In case you need a special processing of `request`, or to modify the `response` for selected endpoints, use the method
|
|
448
443
|
`addExpressMiddleware()` of `EndpointsFactory` (or its alias `use()`). The method has two optional features: a provider
|
|
449
|
-
of [
|
|
444
|
+
of a [context](#context) and an error transformer for adjusting the response status code.
|
|
450
445
|
|
|
451
446
|
```ts
|
|
452
447
|
import { defaultEndpointsFactory } from "express-zod-api";
|
|
@@ -1045,8 +1040,8 @@ test("should respond successfully", async () => {
|
|
|
1045
1040
|
|
|
1046
1041
|
## Testing middlewares
|
|
1047
1042
|
|
|
1048
|
-
Middlewares can also be tested individually using the `testMiddleware()` method. You can also pass `
|
|
1049
|
-
from
|
|
1043
|
+
Middlewares can also be tested individually using the `testMiddleware()` method. You can also pass `ctx` collected
|
|
1044
|
+
from returns of previous middlewares, if the one being tested somehow depends on it. Possible errors would be handled
|
|
1050
1045
|
either by `errorHandler` configured within given `configProps` or `defaultResultHandler`.
|
|
1051
1046
|
|
|
1052
1047
|
```ts
|
|
@@ -1055,8 +1050,8 @@ import { Middleware, testMiddleware } from "express-zod-api";
|
|
|
1055
1050
|
|
|
1056
1051
|
const middleware = new Middleware({
|
|
1057
1052
|
input: z.object({ test: z.string() }),
|
|
1058
|
-
handler: async ({
|
|
1059
|
-
|
|
1053
|
+
handler: async ({ ctx, input: { test } }) => ({
|
|
1054
|
+
collectedContext: Object.keys(ctx),
|
|
1060
1055
|
testLength: test.length,
|
|
1061
1056
|
}),
|
|
1062
1057
|
});
|
|
@@ -1064,10 +1059,10 @@ const middleware = new Middleware({
|
|
|
1064
1059
|
const { output, responseMock, loggerMock } = await testMiddleware({
|
|
1065
1060
|
middleware,
|
|
1066
1061
|
requestProps: { method: "POST", body: { test: "something" } },
|
|
1067
|
-
|
|
1062
|
+
ctx: { prev: "accumulated" }, // responseOptions, configProps, loggerProps
|
|
1068
1063
|
});
|
|
1069
1064
|
expect(loggerMock._getLogs().error).toHaveLength(0);
|
|
1070
|
-
expect(output).toEqual({
|
|
1065
|
+
expect(output).toEqual({ collectedContext: ["prev"], testLength: 9 });
|
|
1071
1066
|
```
|
|
1072
1067
|
|
|
1073
1068
|
# Integration and Documentation
|
|
@@ -1087,6 +1082,7 @@ import { Integration } from "express-zod-api";
|
|
|
1087
1082
|
|
|
1088
1083
|
const client = new Integration({
|
|
1089
1084
|
routing,
|
|
1085
|
+
config,
|
|
1090
1086
|
variant: "client", // <— optional, see also "types" for a DIY solution
|
|
1091
1087
|
});
|
|
1092
1088
|
|
|
@@ -1183,11 +1179,11 @@ new Documentation({
|
|
|
1183
1179
|
## Deprecated schemas and routes
|
|
1184
1180
|
|
|
1185
1181
|
As your API evolves, you may need to mark some parameters or routes as deprecated before deleting them. For this
|
|
1186
|
-
purpose, the `.deprecated()` method is available on each schema
|
|
1182
|
+
purpose, the `.deprecated()` method is available on each schema and `Endpoint`, it's immutable.
|
|
1187
1183
|
You can also deprecate all routes the `Endpoint` assigned to by setting `EndpointsFactory::build({ deprecated: true })`.
|
|
1188
1184
|
|
|
1189
1185
|
```ts
|
|
1190
|
-
import { Routing
|
|
1186
|
+
import { Routing } from "express-zod-api";
|
|
1191
1187
|
import { z } from "zod";
|
|
1192
1188
|
|
|
1193
1189
|
const someEndpoint = factory.build({
|
|
@@ -1199,8 +1195,7 @@ const someEndpoint = factory.build({
|
|
|
1199
1195
|
|
|
1200
1196
|
const routing: Routing = {
|
|
1201
1197
|
v1: oldEndpoint.deprecated(), // deprecates the /v1 path
|
|
1202
|
-
v2:
|
|
1203
|
-
v3: someEndpoint, // the path is assigned with initially deprecated endpoint (also deprecated)
|
|
1198
|
+
v2: someEndpoint, // the path is assigned with initially deprecated endpoint (also deprecated)
|
|
1204
1199
|
};
|
|
1205
1200
|
```
|
|
1206
1201
|
|
|
@@ -1378,7 +1373,7 @@ const subscriptionEndpoint = new EventStreamFactory({
|
|
|
1378
1373
|
time: z.int().positive(),
|
|
1379
1374
|
}).buildVoid({
|
|
1380
1375
|
input: z.object({}), // optional input schema
|
|
1381
|
-
handler: async ({
|
|
1376
|
+
handler: async ({ ctx: { emit, isClosed, signal } }) => {
|
|
1382
1377
|
while (!isClosed()) {
|
|
1383
1378
|
emit("time", Date.now());
|
|
1384
1379
|
await setTimeout(1000);
|
|
@@ -1395,11 +1390,6 @@ framework, [Zod Sockets](https://github.com/RobinTail/zod-sockets), which has si
|
|
|
1395
1390
|
There are some well-known issues and limitations, or third party bugs that cannot be fixed in the usual way, but you
|
|
1396
1391
|
should be aware of them.
|
|
1397
1392
|
|
|
1398
|
-
## TypeError: example is not a function
|
|
1399
|
-
|
|
1400
|
-
If you face this error then [switch your environment to ESM](#environment-preparation).
|
|
1401
|
-
See [issue 2981](https://github.com/RobinTail/express-zod-api/issues/2981) for details.
|
|
1402
|
-
|
|
1403
1393
|
## Excessive properties in endpoint output
|
|
1404
1394
|
|
|
1405
1395
|
The schema validator removes excessive properties by default. However, Typescript
|