express-zod-api 23.4.1 → 24.0.0-beta.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/CHANGELOG.md CHANGED
@@ -1,7 +1,59 @@
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
+ - Despite supporting examples by the new Zod method `.meta()`, users should still use `.example()` to set them;
17
+ - Refer to [Migration guide on Zod 4](https://v4.zod.dev/v4/changelog) for adjusting your schemas;
18
+ - Generating Documentation is partially delegated to Zod 4 `z.toJSONSchema()`:
19
+ - The basic depiction of each schema is now natively performed by Zod 4;
20
+ - Express Zod API implements some overrides and improvements to fit it into OpenAPI 3.1 that extends JSON Schema;
21
+ - The `numericRange` option removed from `Documentation` class constructor argument;
22
+ - The `brandHandling` should consist of postprocessing functions altering the depiction made by Zod 4;
23
+ - The `Depicter` type signature changed;
24
+ - The `optionalPropStyle` option removed from `Integration` class constructor:
25
+ - Use `.optional()` to add question mark to the object property as well as `undefined` to its type;
26
+ - Use `.or(z.undefined())` to add `undefined` to the type of the object property;
27
+ - Reasoning: https://x.com/colinhacks/status/1919292504861491252;
28
+ - `z.any()` and `z.unknown()` are not optional, details: https://v4.zod.dev/v4/changelog#changes-zunknown-optionality.
29
+ - Consider the automated migration using the built-in ESLint rule.
30
+
31
+ ```js
32
+ // eslint.config.mjs — minimal ESLint 9 config to apply migrations automatically using "eslint --fix"
33
+ import parser from "@typescript-eslint/parser";
34
+ import migration from "express-zod-api/migration";
35
+
36
+ export default [
37
+ { languageOptions: { parser }, plugins: { migration } },
38
+ { files: ["**/*.ts"], rules: { "migration/v24": "error" } },
39
+ ];
40
+ ```
41
+
42
+ ```diff
43
+ - import { z } from "zod";
44
+ + import { z } from "zod/v4";
45
+ ```
46
+
3
47
  ## Version 23
4
48
 
49
+ ### v23.5.0
50
+
51
+ - Integer number `format` in generated Documentation now also depends on the `numericRange` option:
52
+ - `int64` is the default format for the range of JavaScript safe integers;
53
+ - `int32` is used when the specified range fits 32 bits (`4294967295`);
54
+ - omitted when `numericRange` is set to `null` (opt-out);
55
+ - The feature suggested by [@crgeary](https://github.com/crgeary).
56
+
5
57
  ### v23.4.1
6
58
 
7
59
  - Fixed headers for an edge case of flat routing with explicit methods:
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. [Coercive schema of Zod](#coercive-schema-of-zod)
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).
@@ -85,9 +84,9 @@ Therefore, many basic tasks can be accomplished faster and easier, in particular
85
84
 
86
85
  These people contributed to the improvement of the framework by reporting bugs, making changes and suggesting ideas:
87
86
 
87
+ [<img src="https://github.com/crgeary.png" alt="@crgeary" width="50px" />](https://github.com/crgeary)
88
88
  [<img src="https://github.com/williamgcampbell.png" alt="@williamgcampbell" width="50px" />](https://github.com/williamgcampbell)
89
89
  [<img src="https://github.com/gmorgen1.png" alt="@gmorgen1" width="50px" />](https://github.com/gmorgen1)
90
- [<img src="https://github.com/crgeary.png" alt="@crgeary" width="50px" />](https://github.com/crgeary)
91
90
  [<img src="https://github.com/danmichaelo.png" alt="@danmichaelo" width="50px" />](https://github.com/danmichaelo)
92
91
  [<img src="https://github.com/james10424.png" alt="@james10424" width="50px" />](https://github.com/james10424)
93
92
  [<img src="https://github.com/APTy.png" alt="@APTy" width="50px" />](https://github.com/APTy)
@@ -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 3.x](https://github.com/colinhacks/zod) including [Zod Plugin](#zod-plugin).
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@3 typescript http-errors
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
@@ -1321,7 +1320,7 @@ You can also deprecate all routes the `Endpoint` assigned to by setting `Endpoin
1321
1320
 
1322
1321
  ```ts
1323
1322
  import { Routing, DependsOnMethod } from "express-zod-api";
1324
- import { z } from "zod";
1323
+ import { z } from "zod/v4";
1325
1324
 
1326
1325
  const someEndpoint = factory.build({
1327
1326
  deprecated: true, // deprecates all routes the endpoint assigned to
@@ -1346,7 +1345,7 @@ need to reuse a handling rule for multiple brands, use the exposed types `Depict
1346
1345
 
1347
1346
  ```ts
1348
1347
  import ts from "typescript";
1349
- import { z } from "zod";
1348
+ import { z } from "zod/v4";
1350
1349
  import {
1351
1350
  Documentation,
1352
1351
  Integration,
@@ -1358,12 +1357,12 @@ const myBrand = Symbol("MamaToldMeImSpecial"); // I recommend to use symbols for
1358
1357
  const myBrandedSchema = z.string().brand(myBrand);
1359
1358
 
1360
1359
  const ruleForDocs: Depicter = (
1361
- schema: typeof myBrandedSchema, // you should assign type yourself
1362
- { next, path, method, isResponse }, // handle a nested schema using next()
1363
- ) => {
1364
- const defaultDepiction = next(schema.unwrap()); // { type: string }
1365
- return { summary: "Special type of data" };
1366
- };
1360
+ { zodSchema, jsonSchema }, // jsonSchema is the default depiction
1361
+ { path, method, isResponse },
1362
+ ) => ({
1363
+ ...jsonSchema,
1364
+ summary: "Special type of data",
1365
+ });
1367
1366
 
1368
1367
  const ruleForClient: Producer = (
1369
1368
  schema: typeof myBrandedSchema, // you should assign type yourself
@@ -1384,16 +1383,6 @@ new Integration({
1384
1383
  There are some well-known issues and limitations, or third party bugs that cannot be fixed in the usual way, but you
1385
1384
  should be aware of them.
1386
1385
 
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
1386
  ## Excessive properties in endpoint output
1398
1387
 
1399
1388
  The schema validator removes excessive properties by default. However, Typescript
@@ -1402,7 +1391,7 @@ in this case during development. You can achieve this verification by assigning
1402
1391
  reusing it in forced type of the output:
1403
1392
 
1404
1393
  ```typescript
1405
- import { z } from "zod";
1394
+ import { z } from "zod/v4";
1406
1395
 
1407
1396
  const output = z.object({
1408
1397
  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: |