Skip to content

Commit 2923d74

Browse files
authored
Remove patchNestJsSwagger in favour of _OPENAPI_METADATA_FACTORY and misc changes (#142)
1 parent c7bbd89 commit 2923d74

24 files changed

Lines changed: 6473 additions & 4858 deletions

.github/workflows/release.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,22 @@ jobs:
3030
- name: Build example app
3131
run: cd packages/example && pnpm run build
3232
- name: Test example app
33-
run: cd packages/example && pnpm run test:e2e
33+
run: cd packages/example && pnpm run test
34+
- name: Cache Playwright Browsers
35+
id: playwright-cache
36+
uses: actions/cache@v4
37+
with:
38+
path: ~/.cache/ms-playwright
39+
key: playwright-${{ runner.os }}-${{ hashFiles('packages/example/package.json') }}
40+
restore-keys: |
41+
playwright-${{ runner.os }}-
42+
- name: Install Playwright Browsers
43+
if: steps.playwright-cache.outputs.cache-hit != 'true'
44+
run: cd packages/example && pnpm exec playwright install --with-deps
45+
- name: Test example app swagger
46+
run: |
47+
cd packages/example && pnpm run start &
48+
cd packages/example && pnpm run test:swagger
3449
3550
- name: Extract version
3651
id: version
@@ -48,6 +63,7 @@ jobs:
4863
run: |
4964
cp logo.svg packages/nestjs-zod
5065
cp README.md packages/nestjs-zod
66+
sed -i 's/\/packages\/example/\.\.\/example/g' packages/nestjs-zod/README.md
5167
5268
- name: Create NPM config
5369
run: cd packages/nestjs-zod && npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN

.github/workflows/test-and-build.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Test and Build
22

33
on:
44
push:
5-
branches: ['main']
5+
branches: ['main', 'v5']
66
pull_request:
7-
branches: ['main']
7+
branches: ['main', 'v5']
88

99
jobs:
1010
test-and-build:
@@ -32,4 +32,20 @@ jobs:
3232
- name: Build example app
3333
run: cd packages/example && pnpm run build
3434
- name: Test example app
35-
run: cd packages/example && pnpm run test:e2e
35+
run: cd packages/example && pnpm run test
36+
- name: Cache Playwright Browsers
37+
id: playwright-cache
38+
uses: actions/cache@v4
39+
with:
40+
path: ~/.cache/ms-playwright
41+
key: playwright-${{ runner.os }}-${{ hashFiles('packages/example/package.json') }}
42+
restore-keys: |
43+
playwright-${{ runner.os }}-
44+
- name: Install Playwright Browsers
45+
if: steps.playwright-cache.outputs.cache-hit != 'true'
46+
run: cd packages/example && pnpm exec playwright install --with-deps
47+
- name: Test example app swagger
48+
run: |
49+
cd packages/example && pnpm run start &
50+
cd packages/example && pnpm run test:swagger
51+

MIGRATION.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
11
# Migration
22

3+
## From version 4.x to 5.x
4+
### `patchNestJsSwagger` has been removed
5+
There is no need to call `patchNestJsSwagger` anymore. The call to `patchNestJsSwagger` can simply be removed:
6+
```diff
7+
- patchNestJsSwagger()
8+
```
9+
10+
### Deprecated `createZodGuard`, `UseZodGuard`, and `ZodGuard`
11+
12+
`createZodGuard` and friends have been deprecated. This was a mistake to add to the library, for a few reasons:
13+
1. It clearly states in the nestjs documentation that guards are only meant for authorization, not for validation:
14+
15+
> Guards have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (like permissions, roles, ACLs, etc.) present at run-time. This is often referred to as authorization
16+
17+
2. `createZodGuard` uses `validate` which is also deprecated
18+
3. `createZodGuard` didn't do anything special. You can create your own guard that does the same thing with very few lines of code. However, it's recommended to use guards for authorization, not exclusively validation. That's not to say you can't use zod inside a guard, but the main purpose of the guard should be authorization.
19+
20+
### Deprecated `validate`
21+
`validate` was a redudant and confusingly named function (it should have been called `parse` if we wanted to keep it). You can simply use the `.parse` function that is attached to the zod schema:
22+
23+
```ts
24+
const MySchema = z.object(...);
25+
const knownData = MySchema.parse(unknownData);
26+
```
27+
28+
Or if you have a DTO:
29+
```ts
30+
class PostDto extends createZodDto(...) {}
31+
PostDto.schema.parse(...)
32+
```
33+
34+
### Deprecated `zodToOpenAPI`
35+
[Zod v4](https://v4.zod.dev/v4#json-schema-conversion) introduces a built-in method of converting zod schemas to OpenAPI, so this function is no longer needed.
36+
37+
```ts
38+
import * as z from "zod";
39+
40+
const mySchema = z.object({name: z.string(), points: z.number()});
41+
42+
z.toJSONSchema(mySchema);
43+
// => {
44+
// type: "object",
45+
// properties: {
46+
// name: {type: "string"},
47+
// points: {type: "number"},
48+
// },
49+
// required: ["name", "points"],
50+
// }
51+
```
52+
353
## From version 3.x to 4.x
454

555
### `nestjs-zod/z` is now `@nest-zod/z`

README.md

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,13 @@
2525

2626
- `createZodDto` - create DTO classes from Zod schemas
2727
- `ZodValidationPipe` - validate `body` / `query` / `params` using Zod DTOs
28-
- `ZodGuard` - guard routes by validating `body` / `query` / `params`
29-
(it can be useful when you want to do that before other guards)
30-
- `UseZodGuard` - alias for `@UseGuards(new ZodGuard(source, schema))`
3128
- `ZodValidationException` - BadRequestException extended with Zod errors
3229
- `zodToOpenAPI` - create OpenAPI declarations from Zod schemas
3330
- OpenAPI support
3431
- `@nestjs/swagger` integration using the patch
3532
- `zodToOpenAPI` - generate highly accurate Swagger Schema
3633
- Zod DTOs can be used in any `@nestjs/swagger` decorator
37-
- Extended Zod schemas for NestJS (`@nest-zod/z`)
38-
- **Note:** _`@nest-zod/z` is deprecated and will not be supported soon. It is recommended to use `zod` directly. See [MIGRATION.md](./MIGRATION.md) for more information._
39-
- `dateString` for dates (supports casting to `Date`)
40-
- `password` for passwords (more complex string rules + OpenAPI conversion)
4134
- Customization - change exception format easily
42-
- Useful helpers for client side error handling (`nestjs-zod/frontend`)
4335

4436
## Installation
4537

@@ -52,7 +44,7 @@ Peer dependencies:
5244
- `zod` - `>= 3.14.3`
5345
- `@nestjs/common` - `>= 8.0.0` (required on server side)
5446
- `@nestjs/core` - `>= 8.0.0` (required on server side)
55-
- `@nestjs/swagger` - `>= 5.0.0` (only when using `patchNestJsSwagger`)
47+
- `@nestjs/swagger` - `>= 5.0.0`
5648

5749
All peer dependencies are marked as optional for better client side usage, but you need to install required ones when using `nestjs-zod` on server side.
5850

@@ -200,6 +192,9 @@ const MyZodValidationPipe = createZodValidationPipe({
200192

201193
## Using ZodGuard
202194

195+
> [!CAUTION]
196+
> `ZodGuard` is deprecated and will not be supported soon. It is recommended to use guards for authorization, not validation. See [MIGRATION.md](./MIGRATION.md) for more information.
197+
203198
Sometimes, we need to validate user input before specific Guards. We can't use Validation Pipe since NestJS Pipes are always executed after Guards.
204199

205200
The solution is `ZodGuard`. It works just like `ZodValidationPipe`, except for that is doesn't transform the input.
@@ -234,6 +229,9 @@ class MyController {
234229

235230
### Creating custom guard
236231

232+
> [!CAUTION]
233+
> `createZodGuard` is deprecated and will not be supported soon. It is recommended to use guards for authorization, not validation. See [MIGRATION.md](./MIGRATION.md) for more information.
234+
237235
```ts
238236
import { createZodGuard } from 'nestjs-zod'
239237

@@ -246,6 +244,9 @@ const MyZodGuard = createZodGuard({
246244

247245
## Create validation from scratch
248246

247+
> [!CAUTION]
248+
> `validate` is deprecated and will not be supported soon. It is recommended to use `.parse` directly. See [MIGRATION.md](./MIGRATION.md) for more information.
249+
249250
If you don't like `ZodGuard` and `ZodValidationPipe`, you can use `validate` function:
250251

251252
```ts
@@ -561,19 +562,13 @@ function mapToFormErrors(issues: ZodIssue[]) {
561562
562563
## OpenAPI (Swagger) support
563564

564-
### Setup
565-
566-
Prerequisites:
565+
> [!Note]
566+
> There used to be a function called `patchNestJsSwagger`. This function has been removed since it is no longer neccessary to call.
567567
568-
- `@nestjs/swagger` with version `^5.0.0` installed
569-
570-
Apply the patch `patchNestJsSwagger()` in your `main.ts` file before setting up your swagger module:
571-
572-
```ts
573-
import { patchNestJsSwagger } from 'nestjs-zod'
574-
575-
patchNestJsSwagger()
576-
```
568+
If you have `@nestjs/swagger` setup, documentation will automatically be generated for:
569+
- Request bodies, if you use `@Body() body: MyDto`
570+
- Response bodies, if you use `@ApiOkResponse({ type: MyDto })`
571+
- Query params, if you use `@Query() query: MyQueryParamsDto`
577572

578573
For addtional documentation, follow the [Nest.js' Swagger Module Guide](https://docs.nestjs.com/openapi/introduction), or you can see the example application guide [here](/packages/example/) .
579574

@@ -592,6 +587,9 @@ const CredentialsSchema = z.object({
592587

593588
### Using zodToOpenAPI
594589

590+
> [!CAUTION]
591+
> `zodToOpenAPI` is deprecated and will not be supported soon, since zod v4 adds built-in support for generating OpenAPI schemas from zod scehams. See [MIGRATION.md](./MIGRATION.md) for more information.
592+
595593
You can convert any Zod schema to an OpenAPI JSON object:
596594

597595
```ts

packages/example/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,10 @@ pids
5454

5555
# Diagnostic reports (https://nodejs.org/api/report.html)
5656
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57+
58+
# Playwright
59+
node_modules/
60+
/test-results/
61+
/playwright-report/
62+
/blob-report/
63+
/playwright/.cache/

packages/example/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,4 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
8383
## License
8484

8585
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
86+

packages/example/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,14 @@
1414
"start:prod": "node dist/main",
1515
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
1616
"test": "jest",
17-
"test:watch": "jest --watch",
18-
"test:cov": "jest --coverage",
19-
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
20-
"test:e2e": "jest --config ./test/jest-e2e.json"
17+
"test:swagger": "playwright test"
2118
},
2219
"dependencies": {
20+
"@nest-zod/z": "workspace:*",
2321
"@nestjs/common": "^11.0.0",
2422
"@nestjs/core": "^11.0.0",
2523
"@nestjs/platform-express": "^11.0.0",
2624
"@nestjs/swagger": "^11.0.1",
27-
"@nest-zod/z": "workspace:*",
2825
"nestjs-zod": "workspace:*",
2926
"reflect-metadata": "^0.2.0",
3027
"rxjs": "^7.8.1",
@@ -34,6 +31,7 @@
3431
"@nestjs/cli": "^11.0.0",
3532
"@nestjs/schematics": "^11.0.0",
3633
"@nestjs/testing": "^11.0.0",
34+
"@playwright/test": "^1.52.0",
3735
"@types/express": "^4.17.17",
3836
"@types/jest": "^29.5.2",
3937
"@types/node": "^22.7.5",
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
/**
4+
* Read environment variables from file.
5+
* https://github.com/motdotla/dotenv
6+
*/
7+
// import dotenv from 'dotenv';
8+
// import path from 'path';
9+
// dotenv.config({ path: path.resolve(__dirname, '.env') });
10+
11+
/**
12+
* See https://playwright.dev/docs/test-configuration.
13+
*/
14+
export default defineConfig({
15+
testDir: './swagger-tests',
16+
/* Run tests in files in parallel */
17+
fullyParallel: true,
18+
/* Fail the build on CI if you accidentally left test.only in the source code. */
19+
forbidOnly: !!process.env.CI,
20+
/* Retry on CI only */
21+
retries: process.env.CI ? 2 : 0,
22+
/* Opt out of parallel tests on CI. */
23+
workers: process.env.CI ? 1 : undefined,
24+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
25+
reporter: 'html',
26+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
27+
use: {
28+
/* Base URL to use in actions like `await page.goto('/')`. */
29+
// baseURL: 'http://127.0.0.1:3000',
30+
31+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
32+
trace: 'on-first-retry',
33+
},
34+
35+
/* Configure projects for major browsers */
36+
projects: [
37+
{
38+
name: 'chromium',
39+
use: { ...devices['Desktop Chrome'] },
40+
},
41+
42+
// {
43+
// name: 'firefox',
44+
// use: { ...devices['Desktop Firefox'] },
45+
// },
46+
47+
// {
48+
// name: 'webkit',
49+
// use: { ...devices['Desktop Safari'] },
50+
// },
51+
52+
/* Test against mobile viewports. */
53+
// {
54+
// name: 'Mobile Chrome',
55+
// use: { ...devices['Pixel 5'] },
56+
// },
57+
// {
58+
// name: 'Mobile Safari',
59+
// use: { ...devices['iPhone 12'] },
60+
// },
61+
62+
/* Test against branded browsers. */
63+
// {
64+
// name: 'Microsoft Edge',
65+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
66+
// },
67+
// {
68+
// name: 'Google Chrome',
69+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
70+
// },
71+
],
72+
73+
/* Run your local dev server before starting the tests */
74+
// webServer: {
75+
// command: 'npm run start',
76+
// url: 'http://127.0.0.1:3000',
77+
// reuseExistingServer: !process.env.CI,
78+
// },
79+
});

packages/example/src/main.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { NestFactory } from '@nestjs/core';
22
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
33
import { AppModule } from './app.module';
4-
import { patchNestJsSwagger } from 'nestjs-zod';
5-
6-
patchNestJsSwagger()
74

85
async function bootstrap() {
96
const app = await NestFactory.create(AppModule);

0 commit comments

Comments
 (0)