Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
dc81cbb
Moving to 3.25 draft (sources and tests).
RobinTail May 17, 2025
ebf0c59
env test: several issues fixed.
RobinTail May 17, 2025
0b65194
Updating a couple snapshots.
RobinTail May 17, 2025
9e0a715
Updating documentation snapshots that gone right.
RobinTail May 17, 2025
bd63db4
Updating snapshots for tests of endpoints factory.
RobinTail May 17, 2025
69dd72c
Changed: toJsonSchema is now top-to-bottom, findRequestTypeDefiningSc…
RobinTail May 17, 2025
7ad8c22
Updating SSE snapshots.
RobinTail May 17, 2025
64b0175
FIX: remap, changed R.clone() to R.map with invoking .clone() on each…
RobinTail May 17, 2025
40bb66c
External bug: adjusting ZodError serialization snapshots.
RobinTail May 17, 2025
8ca2108
rm unref() - no longer needed.
RobinTail May 17, 2025
9670c1f
Adjusting imports in example.
RobinTail May 17, 2025
d66940d
Readme: adjusting zod imports.
RobinTail May 17, 2025
e151423
RM: depictNullable optimization due to changed order of override calls.
RobinTail May 17, 2025
c651bb0
Todays version: overrides order fixed back to bottom-to-top, revertin…
RobinTail May 18, 2025
19b5240
Revert: restoring depictNullable.
RobinTail May 18, 2025
f981d8c
CI: using next tag in validations.
RobinTail May 18, 2025
990c8ee
Add imports migration.
RobinTail May 18, 2025
da5fb7c
Updating example snapshot.
RobinTail May 18, 2025
dc89329
Error caught from .parse() is not similar to one returned by .safePar…
RobinTail May 18, 2025
7995e7b
Update express-zod-api/tests/deep-checks.spec.ts
RobinTail May 18, 2025
ef8c6b8
Restoring env test on transformation examples, rm unused snapshots.
RobinTail May 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/validations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
name: dist
- name: Add dependencies
run: |
yarn add express@${{matrix.express-version}} [email protected] http-errors zod@^4.0.0-beta.20250505T195954
yarn add express@${{matrix.express-version}} [email protected] http-errors zod@next
yarn add -D [email protected] [email protected] vitest tsx
yarn add express-zod-api@./dist.tgz
- name: Run tests
Expand Down
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
### v24.0.0

- Switched to Zod 4:
- Minimum supported version of `zod` is 4.0.0;
- ⚠️This version might not support all new features of Zod 4;
- Minimum supported version of `zod` is 3.25.0, BUT imports MUST be from `zod/v4`;
- Find out why it's so weird here: https://github.com/colinhacks/zod/issues/4371
- `IOSchema` type had to be simplified down to a schema resulting to an `object`, but not an `array`;
- Despite supporting examples by the new Zod method `.meta()`, users should still use `.example()` to set them;
- Refer to [Migration guide on Zod 4](https://v4.zod.dev/v4/changelog) for adjusting your schemas;
Expand Down
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ import { defaultEndpointsFactory } from "express-zod-api";
The endpoint responds with "Hello, World" or "Hello, {name}" if the name is supplied within `GET` request payload.

```typescript
import { z } from "zod";
import { z } from "zod/v4";

const helloWorldEndpoint = defaultEndpointsFactory.build({
// method: "get" (default) or array ["get", "post", ...]
Expand Down Expand Up @@ -325,7 +325,7 @@ Inputs of middlewares are also available to endpoint handlers within `input`.
Here is an example of the authentication middleware, that checks a `key` from input and `token` from headers:

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import createHttpError from "http-errors";
import { Middleware } from "express-zod-api";

Expand Down Expand Up @@ -455,7 +455,7 @@ You can implement additional validations within schemas using refinements.
Validation errors are reported in a response with a status code `400`.

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import { Middleware } from "express-zod-api";

const nicknameConstraintMiddleware = new Middleware({
Expand Down Expand Up @@ -496,7 +496,7 @@ Since parameters of GET requests come in the form of strings, there is often a n
arrays of numbers.

```typescript
import { z } from "zod";
import { z } from "zod/v4";

const getUserEndpoint = endpointsFactory.build({
input: z.object({
Expand Down Expand Up @@ -527,7 +527,7 @@ Here is a recommended solution: it is important to use shallow transformations o
```ts
import camelize from "camelize-ts";
import snakify from "snakify-ts";
import { z } from "zod";
import { z } from "zod/v4";

const endpoint = endpointsFactory.build({
input: z
Expand Down Expand Up @@ -580,7 +580,7 @@ provides your endpoint handler or middleware with a `Date`. It supports the foll
format for the response transmission. Consider the following simplified example for better understanding:

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import { ez, defaultEndpointsFactory } from "express-zod-api";

const updateUserEndpoint = defaultEndpointsFactory.build({
Expand Down Expand Up @@ -790,7 +790,7 @@ In a similar way you can enable request headers as the input source. This is an

```typescript
import { createConfig, Middleware } from "express-zod-api";
import { z } from "zod";
import { z } from "zod/v4";

createConfig({
inputSources: {
Expand Down Expand Up @@ -825,7 +825,7 @@ type DefaultResponse<OUT> =
You can create your own result handler by using this example as a template:

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import {
ResultHandler,
ensureHttpError,
Expand Down Expand Up @@ -951,7 +951,7 @@ which is `express.urlencoded()` by default. The request content type should be `

```ts
import { defaultEndpointsFactory, ez } from "express-zod-api";
import { z } from "zod";
import { z } from "zod/v4";

export const submitFeedbackEndpoint = defaultEndpointsFactory.build({
method: "post",
Expand Down Expand Up @@ -991,7 +991,7 @@ const config = createConfig({
Then use `ez.upload()` schema for a corresponding property. The request content type must be `multipart/form-data`:

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import { ez, defaultEndpointsFactory } from "express-zod-api";

const fileUploadEndpoint = defaultEndpointsFactory.build({
Expand Down Expand Up @@ -1069,7 +1069,7 @@ from outputs of previous middlewares, if the one being tested somehow depends on
either by `errorHandler` configured within given `configProps` or `defaultResultHandler`.

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import { Middleware, testMiddleware } from "express-zod-api";

const middleware = new Middleware({
Expand Down Expand Up @@ -1180,7 +1180,7 @@ Client application can subscribe to the event stream using `EventSource` class i
the implementation emitting the `time` event each second.

```typescript
import { z } from "zod";
import { z } from "zod/v4";
import { EventStreamFactory } from "express-zod-api";
import { setTimeout } from "node:timers/promises";

Expand Down Expand Up @@ -1320,7 +1320,7 @@ You can also deprecate all routes the `Endpoint` assigned to by setting `Endpoin

```ts
import { Routing, DependsOnMethod } from "express-zod-api";
import { z } from "zod";
import { z } from "zod/v4";

const someEndpoint = factory.build({
deprecated: true, // deprecates all routes the endpoint assigned to
Expand All @@ -1345,7 +1345,7 @@ need to reuse a handling rule for multiple brands, use the exposed types `Depict

```ts
import ts from "typescript";
import { z } from "zod";
import { z } from "zod/v4";
import {
Documentation,
Integration,
Expand Down Expand Up @@ -1391,7 +1391,7 @@ in this case during development. You can achieve this verification by assigning
reusing it in forced type of the output:

```typescript
import { z } from "zod";
import { z } from "zod/v4";

const output = z.object({
anything: z.number(),
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/accept-raw.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";
import { defaultEndpointsFactory, ez } from "express-zod-api";

export const rawAcceptingEndpoint = defaultEndpointsFactory.build({
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/create-user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import createHttpError from "http-errors";
import assert from "node:assert/strict";
import { z } from "zod";
import { z } from "zod/v4";
import { statusDependingFactory } from "../factories";

/** @desc depending on the thrown error, the custom result handler of the factory responds slightly differently */
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/delete-user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import createHttpError from "http-errors";
import assert from "node:assert/strict";
import { z } from "zod";
import { z } from "zod/v4";
import { noContentFactory } from "../factories";

/** @desc The endpoint demonstrates no content response established by its factory */
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/list-users.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import z from "zod";
import z from "zod/v4";
import { arrayRespondingFactory } from "../factories";

/**
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/retrieve-user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import createHttpError from "http-errors";
import assert from "node:assert/strict";
import { z } from "zod";
import { z } from "zod/v4";
import { defaultEndpointsFactory } from "express-zod-api";
import { methodProviderMiddleware } from "../middlewares";

Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/send-avatar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";
import { fileSendingEndpointsFactory } from "../factories";
import { readFile } from "node:fs/promises";

Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/stream-avatar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";
import { fileStreamingEndpointsFactory } from "../factories";

export const streamAvatarEndpoint = fileStreamingEndpointsFactory.build({
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/submit-feedback.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defaultEndpointsFactory, ez } from "express-zod-api";
import { z } from "zod";
import { z } from "zod/v4";

export const submitFeedbackEndpoint = defaultEndpointsFactory.build({
method: "post",
Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/time-subscription.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";
import { setTimeout } from "node:timers/promises";
import { eventsFactory } from "../factories";

Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/update-user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import createHttpError from "http-errors";
import assert from "node:assert/strict";
import { z } from "zod";
import { z } from "zod/v4";
import { ez } from "express-zod-api";
import { keyAndTokenAuthenticatedEndpointsFactory } from "../factories";

Expand Down
2 changes: 1 addition & 1 deletion example/endpoints/upload-avatar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";
import { defaultEndpointsFactory, ez } from "express-zod-api";
import { createHash } from "node:crypto";

Expand Down
10 changes: 5 additions & 5 deletions example/example.documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ paths:
id:
type: integer
exclusiveMinimum: 0
exclusiveMaximum: 9007199254740991
maximum: 9007199254740991
required:
- id
required:
Expand All @@ -293,7 +293,7 @@ paths:
id:
type: integer
exclusiveMinimum: 0
exclusiveMaximum: 9007199254740991
maximum: 9007199254740991
required:
- id
required:
Expand Down Expand Up @@ -613,7 +613,7 @@ paths:
data:
type: integer
exclusiveMinimum: 0
exclusiveMaximum: 9007199254740991
maximum: 9007199254740991
event:
type: string
const: time
Expand All @@ -622,7 +622,7 @@ paths:
retry:
type: integer
exclusiveMinimum: 0
exclusiveMaximum: 9007199254740991
maximum: 9007199254740991
required:
- data
- event
Expand Down Expand Up @@ -676,7 +676,7 @@ paths:
crc:
type: integer
exclusiveMinimum: 0
exclusiveMaximum: 9007199254740991
maximum: 9007199254740991
required:
- crc
required:
Expand Down
2 changes: 1 addition & 1 deletion example/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "express-zod-api";
import { authMiddleware } from "./middlewares";
import { createReadStream } from "node:fs";
import { z } from "zod";
import { z } from "zod/v4";

/** @desc This factory extends the default one by enforcing the authentication using the specified middleware */
export const keyAndTokenAuthenticatedEndpointsFactory =
Expand Down
2 changes: 1 addition & 1 deletion example/middlewares.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import createHttpError from "http-errors";
import assert from "node:assert/strict";
import { z } from "zod";
import { z } from "zod/v4";
import { Method, Middleware } from "express-zod-api";

export const authMiddleware = new Middleware({
Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"express-fileupload": "^1.5.0",
"http-errors": "^2.0.0",
"typescript": "^5.1.3",
"zod": "^4.0.0-beta.20250505T012514"
"zod": "3.25.0-beta.20250518T002810"
},
"peerDependenciesMeta": {
"@types/compression": {
Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/src/api-response.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";

export const defaultStatusCodes = {
positive: 200,
Expand Down
4 changes: 2 additions & 2 deletions express-zod-api/src/common-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import type {
$ZodTransform,
$ZodType,
$ZodTypeInternals,
} from "@zod/core";
} from "zod/v4/core";
import { Request } from "express";
import * as R from "ramda";
import { globalRegistry, z } from "zod";
import { globalRegistry, z } from "zod/v4";
import { CommonConfig, InputSource, InputSources } from "./config-type";
import { contentTypes } from "./content-type";
import { OutputValidationError } from "./errors";
Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/src/date-in-schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";

export const ezDateInBrand = Symbol("DateIn");

Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/src/date-out-schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";

export const ezDateOutBrand = Symbol("DateOut");

Expand Down
4 changes: 2 additions & 2 deletions express-zod-api/src/deep-checks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { $ZodType, JSONSchema } from "@zod/core";
import type { $ZodType, JSONSchema } from "zod/v4/core";
import * as R from "ramda";
import { globalRegistry, z } from "zod";
import { globalRegistry, z } from "zod/v4";
import { ezDateInBrand } from "./date-in-schema";
import { ezDateOutBrand } from "./date-out-schema";
import { DeepCheckError } from "./errors";
Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/src/diagnostics.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { z } from "zod/v4";
import { responseVariants } from "./api-response";
import { FlatObject, getRoutePathParams } from "./common-helpers";
import { contentTypes } from "./content-type";
Expand Down
7 changes: 3 additions & 4 deletions express-zod-api/src/documentation-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
$ZodTuple,
$ZodType,
JSONSchema,
} from "@zod/core";
} from "zod/v4/core";
import {
ExamplesObject,
isReferenceObject,
Expand All @@ -23,7 +23,7 @@ import {
TagObject,
} from "openapi3-ts/oas31";
import * as R from "ramda";
import { globalRegistry, z } from "zod";
import { globalRegistry, z } from "zod/v4";
import { ResponseVariant } from "./api-response";
import {
FlatObject,
Expand All @@ -45,7 +45,7 @@ import { ezDateOutBrand } from "./date-out-schema";
import { DocumentationError } from "./errors";
import { ezFileBrand } from "./file-schema";
import { IOSchema } from "./io-schema";
import { flattenIO, unref } from "./json-schema-helpers";
import { flattenIO } from "./json-schema-helpers";
import { Alternatives } from "./logical-container";
import { metaSymbol } from "./metadata";
import { Method } from "./method";
Expand Down Expand Up @@ -463,7 +463,6 @@ const depict = (
unrepresentable: "any",
io: ctx.isResponse ? "output" : "input",
override: (zodCtx) => {
unref(zodCtx.jsonSchema);
const { brand } =
globalRegistry.get(zodCtx.zodSchema)?.[metaSymbol] ?? {};
const depicter =
Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/src/endpoint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Request, Response } from "express";
import * as R from "ramda";
import { globalRegistry, z } from "zod";
import { globalRegistry, z } from "zod/v4";
import { NormalizedResponse, ResponseVariant } from "./api-response";
import { findRequestTypeDefiningSchema } from "./deep-checks";
import {
Expand Down
2 changes: 1 addition & 1 deletion express-zod-api/src/endpoints-factory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Request, Response } from "express";
import { z } from "zod";
import { z } from "zod/v4";
import { EmptyObject, EmptySchema, FlatObject, Tag } from "./common-helpers";
import { Endpoint, Handler } from "./endpoint";
import { IOSchema, getFinalEndpointInputSchema } from "./io-schema";
Expand Down
Loading