express-zod-api 23.5.0 → 24.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 +57 -0
- package/README.md +30 -37
- package/SECURITY.md +1 -0
- package/dist/index.cjs +10 -10
- package/dist/index.d.cts +120 -180
- package/dist/index.d.ts +120 -180
- package/dist/index.js +10 -10
- package/migration/index.cjs +1 -1
- package/migration/index.d.cts +2 -2
- package/migration/index.d.ts +2 -2
- package/migration/index.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Version 24
|
|
4
|
+
|
|
5
|
+
### v24.0.0
|
|
6
|
+
|
|
7
|
+
- Switched to Zod 4:
|
|
8
|
+
- Minimum supported version of `zod` is 3.25.1, BUT imports MUST be from `zod/v4`;
|
|
9
|
+
- Explanation of the versioning strategy: https://github.com/colinhacks/zod/issues/4371;
|
|
10
|
+
- Express Zod API, however, is not aiming to support both Zod 3 and Zod 4 simultaneously due to:
|
|
11
|
+
- incompatibility of data structures;
|
|
12
|
+
- operating composite schemas (need to avoid mixing schemas of different versions);
|
|
13
|
+
- the temporary nature of this transition;
|
|
14
|
+
- the advantages of Zod 4 that provide opportunities to simplifications and corrections of known issues.
|
|
15
|
+
- `IOSchema` type had to be simplified down to a schema resulting to an `object`, but not an `array`;
|
|
16
|
+
- Refer to [Migration guide on Zod 4](https://v4.zod.dev/v4/changelog) for adjusting your schemas;
|
|
17
|
+
- Changes to `ZodType::example()` (Zod plugin method):
|
|
18
|
+
- Now acts as an alias for `ZodType::meta({ examples })`;
|
|
19
|
+
- The argument has to be the output type of the schema (used to be the opposite):
|
|
20
|
+
- This change is only breaking for transforming schemas;
|
|
21
|
+
- In order to specify an input example for a transforming schema the `.example()` method must be called before it;
|
|
22
|
+
- Generating Documentation is mostly delegated to Zod 4 `z.toJSONSchema()`:
|
|
23
|
+
- The basic depiction of each schema is now natively performed by Zod 4;
|
|
24
|
+
- Express Zod API implements some overrides and improvements to fit it into OpenAPI 3.1 that extends JSON Schema;
|
|
25
|
+
- The `numericRange` option removed from `Documentation` class constructor argument;
|
|
26
|
+
- The `brandHandling` should consist of postprocessing functions altering the depiction made by Zod 4;
|
|
27
|
+
- The `Depicter` type signature changed;
|
|
28
|
+
- The `optionalPropStyle` option removed from `Integration` class constructor:
|
|
29
|
+
- Use `.optional()` to add question mark to the object property as well as `undefined` to its type;
|
|
30
|
+
- Use `.or(z.undefined())` to add `undefined` to the type of the object property;
|
|
31
|
+
- Reasoning: https://x.com/colinhacks/status/1919292504861491252;
|
|
32
|
+
- `z.any()` and `z.unknown()` are not optional, details: https://v4.zod.dev/v4/changelog#changes-zunknown-optionality.
|
|
33
|
+
- The `getExamples()` public helper removed — use `.meta()?.examples` instead;
|
|
34
|
+
- Consider the automated migration using the built-in ESLint rule.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
// eslint.config.mjs — minimal ESLint 9 config to apply migrations automatically using "eslint --fix"
|
|
38
|
+
import parser from "@typescript-eslint/parser";
|
|
39
|
+
import migration from "express-zod-api/migration";
|
|
40
|
+
|
|
41
|
+
export default [
|
|
42
|
+
{ languageOptions: { parser }, plugins: { migration } },
|
|
43
|
+
{ files: ["**/*.ts"], rules: { "migration/v24": "error" } },
|
|
44
|
+
];
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```diff
|
|
48
|
+
- import { z } from "zod";
|
|
49
|
+
+ import { z } from "zod/v4";
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```diff
|
|
53
|
+
z.string()
|
|
54
|
+
+ .example("123")
|
|
55
|
+
.transform(Number)
|
|
56
|
+
- .example("123")
|
|
57
|
+
+ .example(123)
|
|
58
|
+
```
|
|
59
|
+
|
|
3
60
|
## Version 23
|
|
4
61
|
|
|
5
62
|
### v23.5.0
|
package/README.md
CHANGED
|
@@ -58,8 +58,7 @@ Start your API server with I/O schema validation and custom middlewares in minut
|
|
|
58
58
|
5. [Deprecated schemas and routes](#deprecated-schemas-and-routes)
|
|
59
59
|
6. [Customizable brands handling](#customizable-brands-handling)
|
|
60
60
|
8. [Caveats](#caveats)
|
|
61
|
-
1. [
|
|
62
|
-
2. [Excessive properties in endpoint output](#excessive-properties-in-endpoint-output)
|
|
61
|
+
1. [Excessive properties in endpoint output](#excessive-properties-in-endpoint-output)
|
|
63
62
|
9. [Your input to my output](#your-input-to-my-output)
|
|
64
63
|
|
|
65
64
|
You can find the release notes and migration guides in [Changelog](CHANGELOG.md).
|
|
@@ -150,7 +149,8 @@ Much can be customized to fit your needs.
|
|
|
150
149
|
|
|
151
150
|
- [Typescript](https://www.typescriptlang.org/) first.
|
|
152
151
|
- Web server — [Express.js](https://expressjs.com/) v5.
|
|
153
|
-
- Schema validation — [Zod
|
|
152
|
+
- Schema validation — [Zod 4.x](https://github.com/colinhacks/zod) including [Zod Plugin](#zod-plugin):
|
|
153
|
+
- For using with Zod 3.x install the framework versions below 24.0.0.
|
|
154
154
|
- Supports any logger having `info()`, `debug()`, `error()` and `warn()` methods;
|
|
155
155
|
- Built-in console logger with colorful and pretty inspections by default.
|
|
156
156
|
- Generators:
|
|
@@ -168,7 +168,7 @@ Install the framework, its peer dependencies and type assistance packages using
|
|
|
168
168
|
|
|
169
169
|
```shell
|
|
170
170
|
# example for yarn:
|
|
171
|
-
yarn add express-zod-api express zod
|
|
171
|
+
yarn add express-zod-api express zod typescript http-errors
|
|
172
172
|
yarn add -D @types/express @types/node @types/http-errors
|
|
173
173
|
```
|
|
174
174
|
|
|
@@ -213,7 +213,7 @@ import { defaultEndpointsFactory } from "express-zod-api";
|
|
|
213
213
|
The endpoint responds with "Hello, World" or "Hello, {name}" if the name is supplied within `GET` request payload.
|
|
214
214
|
|
|
215
215
|
```typescript
|
|
216
|
-
import { z } from "zod";
|
|
216
|
+
import { z } from "zod/v4";
|
|
217
217
|
|
|
218
218
|
const helloWorldEndpoint = defaultEndpointsFactory.build({
|
|
219
219
|
// method: "get" (default) or array ["get", "post", ...]
|
|
@@ -325,7 +325,7 @@ Inputs of middlewares are also available to endpoint handlers within `input`.
|
|
|
325
325
|
Here is an example of the authentication middleware, that checks a `key` from input and `token` from headers:
|
|
326
326
|
|
|
327
327
|
```typescript
|
|
328
|
-
import { z } from "zod";
|
|
328
|
+
import { z } from "zod/v4";
|
|
329
329
|
import createHttpError from "http-errors";
|
|
330
330
|
import { Middleware } from "express-zod-api";
|
|
331
331
|
|
|
@@ -455,7 +455,7 @@ You can implement additional validations within schemas using refinements.
|
|
|
455
455
|
Validation errors are reported in a response with a status code `400`.
|
|
456
456
|
|
|
457
457
|
```typescript
|
|
458
|
-
import { z } from "zod";
|
|
458
|
+
import { z } from "zod/v4";
|
|
459
459
|
import { Middleware } from "express-zod-api";
|
|
460
460
|
|
|
461
461
|
const nicknameConstraintMiddleware = new Middleware({
|
|
@@ -496,7 +496,7 @@ Since parameters of GET requests come in the form of strings, there is often a n
|
|
|
496
496
|
arrays of numbers.
|
|
497
497
|
|
|
498
498
|
```typescript
|
|
499
|
-
import { z } from "zod";
|
|
499
|
+
import { z } from "zod/v4";
|
|
500
500
|
|
|
501
501
|
const getUserEndpoint = endpointsFactory.build({
|
|
502
502
|
input: z.object({
|
|
@@ -527,7 +527,7 @@ Here is a recommended solution: it is important to use shallow transformations o
|
|
|
527
527
|
```ts
|
|
528
528
|
import camelize from "camelize-ts";
|
|
529
529
|
import snakify from "snakify-ts";
|
|
530
|
-
import { z } from "zod";
|
|
530
|
+
import { z } from "zod/v4";
|
|
531
531
|
|
|
532
532
|
const endpoint = endpointsFactory.build({
|
|
533
533
|
input: z
|
|
@@ -580,7 +580,7 @@ provides your endpoint handler or middleware with a `Date`. It supports the foll
|
|
|
580
580
|
format for the response transmission. Consider the following simplified example for better understanding:
|
|
581
581
|
|
|
582
582
|
```typescript
|
|
583
|
-
import { z } from "zod";
|
|
583
|
+
import { z } from "zod/v4";
|
|
584
584
|
import { ez, defaultEndpointsFactory } from "express-zod-api";
|
|
585
585
|
|
|
586
586
|
const updateUserEndpoint = defaultEndpointsFactory.build({
|
|
@@ -790,7 +790,7 @@ In a similar way you can enable request headers as the input source. This is an
|
|
|
790
790
|
|
|
791
791
|
```typescript
|
|
792
792
|
import { createConfig, Middleware } from "express-zod-api";
|
|
793
|
-
import { z } from "zod";
|
|
793
|
+
import { z } from "zod/v4";
|
|
794
794
|
|
|
795
795
|
createConfig({
|
|
796
796
|
inputSources: {
|
|
@@ -825,7 +825,7 @@ type DefaultResponse<OUT> =
|
|
|
825
825
|
You can create your own result handler by using this example as a template:
|
|
826
826
|
|
|
827
827
|
```typescript
|
|
828
|
-
import { z } from "zod";
|
|
828
|
+
import { z } from "zod/v4";
|
|
829
829
|
import {
|
|
830
830
|
ResultHandler,
|
|
831
831
|
ensureHttpError,
|
|
@@ -951,7 +951,7 @@ which is `express.urlencoded()` by default. The request content type should be `
|
|
|
951
951
|
|
|
952
952
|
```ts
|
|
953
953
|
import { defaultEndpointsFactory, ez } from "express-zod-api";
|
|
954
|
-
import { z } from "zod";
|
|
954
|
+
import { z } from "zod/v4";
|
|
955
955
|
|
|
956
956
|
export const submitFeedbackEndpoint = defaultEndpointsFactory.build({
|
|
957
957
|
method: "post",
|
|
@@ -991,7 +991,7 @@ const config = createConfig({
|
|
|
991
991
|
Then use `ez.upload()` schema for a corresponding property. The request content type must be `multipart/form-data`:
|
|
992
992
|
|
|
993
993
|
```typescript
|
|
994
|
-
import { z } from "zod";
|
|
994
|
+
import { z } from "zod/v4";
|
|
995
995
|
import { ez, defaultEndpointsFactory } from "express-zod-api";
|
|
996
996
|
|
|
997
997
|
const fileUploadEndpoint = defaultEndpointsFactory.build({
|
|
@@ -1069,7 +1069,7 @@ from outputs of previous middlewares, if the one being tested somehow depends on
|
|
|
1069
1069
|
either by `errorHandler` configured within given `configProps` or `defaultResultHandler`.
|
|
1070
1070
|
|
|
1071
1071
|
```typescript
|
|
1072
|
-
import { z } from "zod";
|
|
1072
|
+
import { z } from "zod/v4";
|
|
1073
1073
|
import { Middleware, testMiddleware } from "express-zod-api";
|
|
1074
1074
|
|
|
1075
1075
|
const middleware = new Middleware({
|
|
@@ -1180,7 +1180,7 @@ Client application can subscribe to the event stream using `EventSource` class i
|
|
|
1180
1180
|
the implementation emitting the `time` event each second.
|
|
1181
1181
|
|
|
1182
1182
|
```typescript
|
|
1183
|
-
import { z } from "zod";
|
|
1183
|
+
import { z } from "zod/v4";
|
|
1184
1184
|
import { EventStreamFactory } from "express-zod-api";
|
|
1185
1185
|
import { setTimeout } from "node:timers/promises";
|
|
1186
1186
|
|
|
@@ -1223,7 +1223,6 @@ import { Integration } from "express-zod-api";
|
|
|
1223
1223
|
const client = new Integration({
|
|
1224
1224
|
routing,
|
|
1225
1225
|
variant: "client", // <— optional, see also "types" for a DIY solution
|
|
1226
|
-
optionalPropStyle: { withQuestionMark: true, withUndefined: true }, // optional
|
|
1227
1226
|
});
|
|
1228
1227
|
|
|
1229
1228
|
const prettierFormattedTypescriptCode = await client.printFormatted(); // or just .print() for unformatted
|
|
@@ -1272,7 +1271,11 @@ const exampleEndpoint = defaultEndpointsFactory.build({
|
|
|
1272
1271
|
shortDescription: "Retrieves the user.", // <—— this becomes the summary line
|
|
1273
1272
|
description: "The detailed explanaition on what this endpoint does.",
|
|
1274
1273
|
input: z.object({
|
|
1275
|
-
id: z
|
|
1274
|
+
id: z
|
|
1275
|
+
.string()
|
|
1276
|
+
.example("123") // input examples should be set before transformations
|
|
1277
|
+
.transform(Number)
|
|
1278
|
+
.describe("the ID of the user"),
|
|
1276
1279
|
}),
|
|
1277
1280
|
// ..., similarly for output and middlewares
|
|
1278
1281
|
});
|
|
@@ -1321,7 +1324,7 @@ You can also deprecate all routes the `Endpoint` assigned to by setting `Endpoin
|
|
|
1321
1324
|
|
|
1322
1325
|
```ts
|
|
1323
1326
|
import { Routing, DependsOnMethod } from "express-zod-api";
|
|
1324
|
-
import { z } from "zod";
|
|
1327
|
+
import { z } from "zod/v4";
|
|
1325
1328
|
|
|
1326
1329
|
const someEndpoint = factory.build({
|
|
1327
1330
|
deprecated: true, // deprecates all routes the endpoint assigned to
|
|
@@ -1346,7 +1349,7 @@ need to reuse a handling rule for multiple brands, use the exposed types `Depict
|
|
|
1346
1349
|
|
|
1347
1350
|
```ts
|
|
1348
1351
|
import ts from "typescript";
|
|
1349
|
-
import { z } from "zod";
|
|
1352
|
+
import { z } from "zod/v4";
|
|
1350
1353
|
import {
|
|
1351
1354
|
Documentation,
|
|
1352
1355
|
Integration,
|
|
@@ -1358,12 +1361,12 @@ const myBrand = Symbol("MamaToldMeImSpecial"); // I recommend to use symbols for
|
|
|
1358
1361
|
const myBrandedSchema = z.string().brand(myBrand);
|
|
1359
1362
|
|
|
1360
1363
|
const ruleForDocs: Depicter = (
|
|
1361
|
-
|
|
1362
|
-
{
|
|
1363
|
-
) => {
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
};
|
|
1364
|
+
{ zodSchema, jsonSchema }, // jsonSchema is the default depiction
|
|
1365
|
+
{ path, method, isResponse },
|
|
1366
|
+
) => ({
|
|
1367
|
+
...jsonSchema,
|
|
1368
|
+
summary: "Special type of data",
|
|
1369
|
+
});
|
|
1367
1370
|
|
|
1368
1371
|
const ruleForClient: Producer = (
|
|
1369
1372
|
schema: typeof myBrandedSchema, // you should assign type yourself
|
|
@@ -1384,16 +1387,6 @@ new Integration({
|
|
|
1384
1387
|
There are some well-known issues and limitations, or third party bugs that cannot be fixed in the usual way, but you
|
|
1385
1388
|
should be aware of them.
|
|
1386
1389
|
|
|
1387
|
-
## Coercive schema of Zod
|
|
1388
|
-
|
|
1389
|
-
Despite being supported by the framework, `z.coerce.*` schema
|
|
1390
|
-
[does not work intuitively](https://github.com/RobinTail/express-zod-api/issues/759).
|
|
1391
|
-
Please be aware that `z.coerce.number()` and `z.number({ coerce: true })` (being typed not well) still will NOT allow
|
|
1392
|
-
you to assign anything but number. Moreover, coercive schemas are not fail-safe and their methods `.isOptional()` and
|
|
1393
|
-
`.isNullable()` [are buggy](https://github.com/colinhacks/zod/issues/1911). If possible, try to avoid using this type
|
|
1394
|
-
of schema. This issue [will NOT be fixed](https://github.com/colinhacks/zod/issues/1760#issuecomment-1407816838) in
|
|
1395
|
-
Zod version 3.x.
|
|
1396
|
-
|
|
1397
1390
|
## Excessive properties in endpoint output
|
|
1398
1391
|
|
|
1399
1392
|
The schema validator removes excessive properties by default. However, Typescript
|
|
@@ -1402,7 +1395,7 @@ in this case during development. You can achieve this verification by assigning
|
|
|
1402
1395
|
reusing it in forced type of the output:
|
|
1403
1396
|
|
|
1404
1397
|
```typescript
|
|
1405
|
-
import { z } from "zod";
|
|
1398
|
+
import { z } from "zod/v4";
|
|
1406
1399
|
|
|
1407
1400
|
const output = z.object({
|
|
1408
1401
|
anything: z.number(),
|
package/SECURITY.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| Version | Code name | Release | Supported |
|
|
6
6
|
| ------: | :------------ | :------ | :----------------: |
|
|
7
|
+
| 24.x.x | Ashley | 06.2025 | :white_check_mark: |
|
|
7
8
|
| 23.x.x | Sonia | 04.2025 | :white_check_mark: |
|
|
8
9
|
| 22.x.x | Tai | 01.2025 | :white_check_mark: |
|
|
9
10
|
| 21.x.x | Kesaria | 11.2024 | :white_check_mark: |
|