@nest-openapi/validator 0.1.0 → 0.1.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/README.md CHANGED
@@ -4,323 +4,108 @@
4
4
 
5
5
  <h1 align="center">@nest-openapi</h1>
6
6
 
7
- <p align="center"><strong>OpenAPI-first validation for NestJS</strong></p>
7
+ <p align="center"><strong>OpenAPIfirst utilities for NestJS</strong></p>
8
8
 
9
9
  <p align="center">
10
- Single source of truth · Drop-in for existing controllers · Fast by design
10
+ Single source of truth · Dropin for NestJS · Fast by design
11
11
  </p>
12
12
 
13
- [![NPM version](https://img.shields.io/npm/v/%40nest-openapi%2Fvalidator.svg)](https://www.npmjs.com/package/%40nest-openapi%2Fvalidator)
14
13
  ![GitHub License](https://img.shields.io/github/license/ts-oas/nest-openapi)
15
- ![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/%40nest-openapi%2Fvalidator)
16
14
 
17
15
  ## Overview
18
16
 
19
- `@nest-openapi` is a light-weight, focused toolkit for OpenAPI-driven NestJS apps.
20
- Today it ships the **request/response validator** that derives schemas from your OpenAPI spec—so you don’t duplicate DTOs or hand-roll validation rules.
17
+ `@nest-openapi` is a modern, modular set of utilities for building OpenAPIdriven NestJS apps.
21
18
 
22
- - **Single Source of Truth** — The OpenAPI spec is the contract; validation is generated from it.
23
- - **Drop-in for NestJS** — Add a module; existing controllers keep working.
24
- - **Fast by Design** — AJV under the hood, with caching and optional pre-compilation.
25
- - **Express & Fastify** — Platform-agnostic validation.
26
- - **Fine-Grained Control** — Per-route opt-out and overrides.
19
+ - **Single Source of Truth** — The OpenAPI spec is the contract; validation and serialization derive from it.
20
+ - **Dropin for NestJS** — Works with existing controllers and routes.
21
+ - **Fast by Design** — AJV validation and fast-json-stringify serialization with caching and precompilation.
22
+ - **Express & Fastify** — Platformagnostic support.
23
+ - **FineGrained Control** — Perroute optout and overrides.
27
24
 
28
- ## Package
25
+ ### Packages
29
26
 
30
- - **`@nest-openapi/validator`** — Automatic request/response validation using your OpenAPI 3.x spec.
27
+ - [**`@nest-openapi/validator`**](https://nest-openapi.github.io/validator/) — Automatic request/response validation using your OpenAPI specification.
31
28
 
32
- ## Install
33
-
34
- ```bash
35
- npm i @nest-openapi/validator
36
- ```
29
+ - [**`@nest-openapi/serializer`**](https://nest-openapi.github.io/serializer/) — High‑performance response serialization based on your OpenAPI 3.x specification.
37
30
 
38
31
  ---
39
32
 
40
- ## Quick Start
33
+ ## Get Started
41
34
 
42
- ### Basic Usage
35
+ ### @nest-openapi/validator
43
36
 
44
- ```typescript
45
- // app.module.ts
46
- import { OpenApiValidatorModule } from "@nest-openapi/validator";
47
- import * as openApiSpec from "./openapi.json";
37
+ [![NPM – validator](https://img.shields.io/npm/v/%40nest-openapi%2Fvalidator.svg)](https://www.npmjs.com/package/%40nest-openapi%2Fvalidator)
38
+ ![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/%40nest-openapi%2Fvalidator.svg)
48
39
 
49
- @Module({
50
- imports: [
51
- OpenApiValidatorModule.forRoot({
52
- specSource: { type: "object", spec: openApiSpec },
53
- }),
54
- ],
55
- })
56
- export class AppModule {}
40
+ Install:
57
41
 
58
- // That's it! All routes automatically validated
42
+ ```bash
43
+ npm i @nest-openapi/validator
59
44
  ```
60
45
 
61
- ### Advanced / Async Configuration
46
+ Minimal setup:
62
47
 
63
48
  ```typescript
64
49
  // app.module.ts
50
+ import { Module } from "@nestjs/common";
51
+ import { OpenAPIValidatorModule } from "@nest-openapi/validator";
52
+ import * as openApiSpec from "./openapi.json";
53
+
65
54
  @Module({
66
55
  imports: [
67
- OpenApiValidatorModule.forRootAsync({
68
- imports: [ConfigModule],
69
- useFactory: (config: ConfigService) => ({
70
- specSource: { type: "object", spec: config.getOpenApiSpec() },
71
- options: {
72
- ajv: {
73
- options: { strict: false },
74
- configure: (ajv) => {
75
- addFormats(ajv); // import addFormats from 'ajv-formats';
76
- },
77
- },
78
- requestValidation: {
79
- enable: false,
80
- },
81
- responseValidation: {
82
- enable: true,
83
- onValidationFailed: (context, errors) => {
84
- console.log(errors);
85
- },
86
- },
87
- },
88
- }),
89
- inject: [ConfigService],
56
+ OpenAPIValidatorModule.forRoot({
57
+ specSource: { type: "object", spec: openApiSpec },
90
58
  }),
91
59
  ],
92
60
  })
93
61
  export class AppModule {}
94
62
  ```
95
63
 
96
- ## Configuration Options
97
-
98
- | Option | Type | Default | Description |
99
- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
100
- | [`specSource`](#specsource) | `{ type: "object"; spec: OpenAPISpec } \| { type: "url"; spec: string } \| { type: "file"; spec: string }` | — | Provide your OpenAPI 3.x spec as an object, or point to it via URL or file path. |
101
- | [`requestValidation`](#requestvalidation) | `RequestValidationOptions` | see [below](#requestvalidation) | Controls validation of incoming requests. |
102
- | [`responseValidation`](#responsevalidation) | `ResponseValidationOptions` | see [below](#responsevalidation) | Controls validation of outgoing responses. |
103
- | [`ajv`](#ajv) | `Ajv \| { options?: AjvOptions; configure?: (ajv: Ajv) => void }` | see [below](#ajv) | Override the default ajv instance or configure it |
104
- | `precompileSchemas` | `boolean` | `false` | Precompile all route schemas during application bootstrap. This removes the first-request latency at the cost of longer start-up time. |
105
- | `debug` | `boolean` | `false` | Verbose logs for troubleshooting. |
106
-
107
- ### `specSource`
108
-
109
- | Type | Type | Typical use |
110
- | ---------- | ------------- | ------------------------------------------------ |
111
- | `"object"` | `OpenAPISpec` | Static spec object. |
112
- | `"url"` | `string` | Link to a centralized or externally hosted spec. |
113
- | `"file"` | `string` | Local file path to a json file. |
114
-
115
- ### `requestValidation`
116
-
117
- | Option | Type | Default | Description |
118
- | -------------------- | --------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
119
- | `enable` | `boolean` | `true` | Enable request validation globally. |
120
- | `transform` | `boolean` | `false` | Coerce/transform inputs where schema allows (e.g., `"42"` → `42`). |
121
- | `onValidationFailed` | `(ctx: ExecutionContext, errors: ValidationError[]) => void \| never` | throws `BadRequestException` with validation errors | Custom handler. Transform, throw your own exception, or log/ignore. |
122
-
123
- ### `responseValidation`
124
-
125
- | Option | Type | Default | Description |
126
- | -------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
127
- | `enable` | `boolean` | `false` | Enable response validation globally. |
128
- | `skipErrorResponses` | `boolean` | `true` | Skip validation for error responses (4xx/5xx status codes). Cant validate thrown errors, see [here](#error-response-validation). |
129
- | `onValidationFailed` | `(ctx: ExecutionContext, errors: ValidationError[]) => void \| never` | warns and throws `InternalServer ErrorException` without validation errors | Custom handler. Transform, throw your own exception, or log/ignore. |
130
-
131
- ### `ajv`
64
+ All routes are automatically validated. **For advanced configuration, see [the docs](https://nest-openapi.github.io/validator/)**.
132
65
 
133
- | Option | Type | Default | Description |
134
- | ----------- | -------------------- | ------------- | ----------------------------------------------------------------------- |
135
- | (itself) | `Ajv` | a v8 instance | Supply a fully configured AJV instance. |
136
- | `options` | `AjvOptions` | — | Initialize the internal AJV with these options (e.g., `strict: false`). |
137
- | `configure` | `(ajv: Ajv) => void` | — | Hook to extend the instance (e.g., `addFormats(ajv)`). |
66
+ ### @nest-openapi/serializer
138
67
 
139
- ## Decorators
68
+ [![NPM – serializer](https://img.shields.io/npm/v/%40nest-openapi%2Fserializer.svg)](https://www.npmjs.com/package/%40nest-openapi%2Fserializer)
69
+ ![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/%40nest-openapi%2Fserializer.svg)
140
70
 
141
- ### Per-route control (skip/override)
71
+ Install:
142
72
 
143
- ```typescript
144
- import { Validate } from "@nest-openapi/validator";
145
-
146
- @Controller("users")
147
- export class UsersController {
148
- @Post()
149
- @Validate({ request: false }) // Skip request validation for this route
150
- createUser(@Body() userData: any) {
151
- return this.usersService.create(userData);
152
- }
153
-
154
- @Get(":id")
155
- @Validate({ request: { param: false }, response: false }) // Skip param and response validation for this route
156
- getUser(@Param("id") id: string) {
157
- return this.usersService.findById(id);
158
- }
159
- }
160
- ```
161
-
162
- ## Manual Validation
163
-
164
- Inject the `OpenApiValidatorService` using the `OPENAPI_VALIDATOR` token for custom validation logic in guards, filters, services, or middleware:
165
-
166
- ```typescript
167
- import { Injectable, Inject } from "@nestjs/common";
168
- import { HttpArgumentsHost } from "@nestjs/common/interfaces";
169
- import {
170
- OPENAPI_VALIDATOR,
171
- OpenApiValidatorService,
172
- } from "@nest-openapi/validator";
173
-
174
- @Injectable()
175
- export class MyService {
176
- constructor(
177
- @Inject(OPENAPI_VALIDATOR)
178
- private readonly validator: OpenApiValidatorService
179
- ) {}
180
-
181
- validateData(httpContext: HttpArgumentsHost, responseBody) {
182
- // Validate requests manually
183
- const bodyOnlyErrors = this.validator.validateRequest(httpContext, {
184
- body: true,
185
- params: false,
186
- query: false,
187
- });
188
-
189
- // Validate responses manually
190
- const responseErrors = this.validator.validateResponse(
191
- httpContext,
192
- statusCode,
193
- responseBody
194
- );
195
- }
196
- }
197
- ```
198
-
199
- ### Error Response Validation
200
-
201
- By default, the response validation interceptor only validates successful responses that flow through the normal pipeline. However, error responses (like `NotFoundException`, `BadRequestException`, etc.) bypass interceptors and go through exception filters.
202
-
203
- To validate error responses, inject the validator service in your exception filter:
204
-
205
- ```typescript
206
- import {
207
- Catch,
208
- ExceptionFilter,
209
- ArgumentsHost,
210
- Injectable,
211
- Inject,
212
- } from "@nestjs/common";
213
- import {
214
- OPENAPI_VALIDATOR,
215
- OpenApiValidatorService,
216
- } from "@nest-openapi/validator";
217
-
218
- @Catch()
219
- @Injectable()
220
- export class GlobalExceptionFilter implements ExceptionFilter {
221
- constructor(
222
- @Inject(OPENAPI_VALIDATOR)
223
- private readonly validator: OpenApiValidatorService
224
- ) {}
225
-
226
- catch(exception: any, host: ArgumentsHost) {
227
- const ctx = host.switchToHttp();
228
- const response = ctx.getResponse();
229
-
230
- const status = exception.getStatus?.() || 500;
231
- const responseBody = {
232
- message: exception.message,
233
- statusCode: status,
234
- timestamp: new Date().toISOString(),
235
- };
236
-
237
- const validationErrors = this.validator.validateResponse(
238
- ctx,
239
- status,
240
- responseBody
241
- );
242
-
243
- if (validationErrors.length > 0) {
244
- console.warn("Error response validation failed:", validationErrors);
245
- // Handle validation errors as needed
246
- }
247
-
248
- response.status(status).json(responseBody);
249
- }
250
- }
73
+ ```bash
74
+ npm i @nest-openapi/serializer
251
75
  ```
252
76
 
253
- Then register your exception filter:
77
+ Minimal setup:
254
78
 
255
79
  ```typescript
256
80
  // app.module.ts
81
+ import { Module } from "@nestjs/common";
82
+ import { OpenAPISerializerModule } from "@nest-openapi/serializer";
83
+ import * as openApiSpec from "./openapi.json";
84
+
257
85
  @Module({
258
- providers: [
259
- {
260
- provide: APP_FILTER,
261
- useClass: GlobalExceptionFilter,
262
- },
86
+ imports: [
87
+ OpenAPISerializerModule.forRoot({
88
+ specSource: { type: "object", spec: openApiSpec },
89
+ responseSerialization: { enable: true, skipErrorResponses: true },
90
+ }),
263
91
  ],
264
92
  })
265
93
  export class AppModule {}
266
94
  ```
267
95
 
268
- ## Error Handling
269
-
270
- ### Handle Validation Errors
271
-
272
- By default, the library throws:
96
+ Successful responses are automatically serialized. **For advanced configuration, see [the docs](https://nest-openapi.github.io/serializer/)**.
273
97
 
274
- - `BadRequestException` for request validation failures, with detailed validation errors.
275
- - `InternalServerErrorException` for response validation failures (without detailed errors, unless you provide a custom handler).
276
-
277
- Validation errors follow the AJV `ErrorObject` format, extended with a `validationType` property:
278
-
279
- ```json
280
- {
281
- "message": "Validation failed",
282
- "errors": [
283
- {
284
- "validationType": "body",
285
- "instancePath": "/title",
286
- "schemaPath": "#/properties/title/type",
287
- "keyword": "type",
288
- "params": { "type": "string" },
289
- "message": "must be string"
290
- }
291
- ]
292
- }
293
- ```
98
+ ---
294
99
 
295
- You can override this behavior using the onValidationFailed handler option in [requestValidation](#requestvalidation) or [responseValidation](#responsevalidation).
100
+ ## Compatibility
296
101
 
297
- Inside your handler, you can whether:
102
+ - Works with NestJS v9+
103
+ - Supports Express and Fastify adopters
298
104
 
299
- - Transform the error list and throw a custom exception.
300
- - Log and ignore errors (return without throwing).
105
+ ## Contributing
301
106
 
302
- ```typescript
303
- OpenApiValidatorModule.forRoot({
304
- specSource: { type: "object", spec: openApiSpec },
305
- requestValidation: {
306
- enable: true,
307
- onValidationFailed: (context, errors) => {
308
- // Custom error handling
309
- throw new BadRequestException({
310
- status: "validation_failed",
311
- issues: errors.map((e) => ({
312
- path: e.instancePath,
313
- message: e.message,
314
- received: e.data,
315
- })),
316
- });
317
- },
318
- },
319
- });
320
- ```
107
+ Issues and PRs are welcome. Please check the package folders and docs before opening an issue.
321
108
 
322
- ## Performance and Compatibility
109
+ ## License
323
110
 
324
- - Optional schema [pre-compilation](#configuration-options) removes first-hit latency at the cost of longer startup.
325
- - Express and Fastify adopters are supported.
326
- - Supports NestJS version >= 9
111
+ MIT © `@nest-openapi`
package/dist/index.cjs CHANGED
@@ -40,8 +40,8 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
40
40
  var index_exports = {};
41
41
  __export(index_exports, {
42
42
  OPENAPI_VALIDATOR: () => OPENAPI_VALIDATOR,
43
- OpenApiValidatorModule: () => OpenApiValidatorModule,
44
- OpenApiValidatorService: () => OpenApiValidatorService,
43
+ OpenAPIValidatorModule: () => OpenAPIValidatorModule,
44
+ OpenAPIValidatorService: () => OpenAPIValidatorService,
45
45
  Validate: () => Validate
46
46
  });
47
47
  module.exports = __toCommonJS(index_exports);
@@ -54,9 +54,14 @@ var import_core3 = require("@nestjs/core");
54
54
  var import_common = require("@nestjs/common");
55
55
  var import_runtime = require("@nest-openapi/runtime");
56
56
  var import_ajv = __toESM(require("ajv"), 1);
57
- var OPENAPI_VALIDATOR_OPTIONS = "OPENAPI_VALIDATOR_OPTIONS";
58
- var OPENAPI_VALIDATOR = "OPENAPI_VALIDATOR";
59
- var OpenApiValidatorService = class {
57
+
58
+ // src/types/validator-options.interface.ts
59
+ var OPENAPI_VALIDATOR_RUNTIME = Symbol("OPENAPI_VALIDATOR_RUNTIME");
60
+ var OPENAPI_VALIDATOR_OPTIONS = Symbol("OPENAPI_VALIDATOR_OPTIONS");
61
+
62
+ // src/services/openapi-validator.service.ts
63
+ var OPENAPI_VALIDATOR = Symbol("OPENAPI_VALIDATOR");
64
+ var OpenAPIValidatorService = class {
60
65
  constructor(runtime, options) {
61
66
  this.runtime = runtime;
62
67
  this.options = options;
@@ -78,7 +83,7 @@ var OpenApiValidatorService = class {
78
83
  ${JSON.stringify(opts, null, 2)}`);
79
84
  }
80
85
  }
81
- logger = new import_common.Logger("OpenApiValidator");
86
+ logger = new import_common.Logger("OpenAPIValidator");
82
87
  ajv;
83
88
  openApiSpec;
84
89
  debugLog;
@@ -337,11 +342,11 @@ ${JSON.stringify(data, null, 2)}`);
337
342
  };
338
343
  }
339
344
  };
340
- OpenApiValidatorService = __decorateClass([
345
+ OpenAPIValidatorService = __decorateClass([
341
346
  (0, import_common.Injectable)(),
342
- __decorateParam(0, (0, import_common.Inject)(import_runtime.OpenApiRuntimeService)),
347
+ __decorateParam(0, (0, import_common.Inject)(OPENAPI_VALIDATOR_RUNTIME)),
343
348
  __decorateParam(1, (0, import_common.Inject)(OPENAPI_VALIDATOR_OPTIONS))
344
- ], OpenApiValidatorService);
349
+ ], OpenAPIValidatorService);
345
350
 
346
351
  // src/interceptors/request-validation.interceptor.ts
347
352
  var import_common3 = require("@nestjs/common");
@@ -350,8 +355,8 @@ var import_runtime3 = require("@nest-openapi/runtime");
350
355
 
351
356
  // src/decorators/validate.decorator.ts
352
357
  var import_common2 = require("@nestjs/common");
353
- var VALIDATE_KEY = "VALIDATE";
354
- var Validate = (options = {}) => (0, import_common2.SetMetadata)(VALIDATE_KEY, options);
358
+ var VALIDATE_OVERRIDE = Symbol("VALIDATE_OVERRIDE");
359
+ var Validate = (options = {}) => (0, import_common2.SetMetadata)(VALIDATE_OVERRIDE, options);
355
360
 
356
361
  // src/interceptors/request-validation.interceptor.ts
357
362
  var RequestValidationInterceptor = class {
@@ -360,7 +365,7 @@ var RequestValidationInterceptor = class {
360
365
  this.reflector = reflector;
361
366
  this.debugLog = import_runtime3.DebugUtil.createDebugFn(this.logger, this.validatorService.validationOptions.debug || false);
362
367
  }
363
- logger = new import_common3.Logger("OpenApiValidator");
368
+ logger = new import_common3.Logger("OpenAPIValidator");
364
369
  debugLog;
365
370
  async intercept(context, next) {
366
371
  if (!this.validatorService.openApiSpec) {
@@ -394,7 +399,7 @@ var RequestValidationInterceptor = class {
394
399
  }
395
400
  getValidationDecorator(context) {
396
401
  const validateMetadata = this.reflector.getAllAndOverride(
397
- VALIDATE_KEY,
402
+ VALIDATE_OVERRIDE,
398
403
  [context.getHandler(), context.getClass()]
399
404
  );
400
405
  if (validateMetadata) {
@@ -437,7 +442,7 @@ var ResponseValidationInterceptor = class {
437
442
  this.reflector = reflector;
438
443
  this.debugLog = import_runtime5.DebugUtil.createDebugFn(this.logger, this.validatorService.validationOptions.debug || false);
439
444
  }
440
- logger = new import_common4.Logger("OpenApiValidator");
445
+ logger = new import_common4.Logger("OpenAPIValidator");
441
446
  debugLog;
442
447
  intercept(context, next) {
443
448
  if (!this.validatorService.openApiSpec) {
@@ -477,7 +482,7 @@ var ResponseValidationInterceptor = class {
477
482
  }
478
483
  shouldValidateResponse(context) {
479
484
  const validateMetadata = this.reflector.getAllAndOverride(
480
- VALIDATE_KEY,
485
+ VALIDATE_OVERRIDE,
481
486
  [context.getHandler(), context.getClass()]
482
487
  );
483
488
  if (validateMetadata) {
@@ -501,7 +506,7 @@ ResponseValidationInterceptor = __decorateClass([
501
506
 
502
507
  // src/modules/openapi-validator.module.ts
503
508
  var import_runtime7 = require("@nest-openapi/runtime");
504
- var OpenApiValidatorModule = class {
509
+ var OpenAPIValidatorModule = class {
505
510
  /**
506
511
  * Configure the OpenAPI validator module with static options
507
512
  */
@@ -525,16 +530,12 @@ var OpenApiValidatorModule = class {
525
530
  },
526
531
  // Core services
527
532
  {
528
- provide: import_runtime7.OpenApiRuntimeService,
529
- useFactory: async (runtimeOptions) => {
530
- const svc = new import_runtime7.OpenApiRuntimeService(runtimeOptions);
531
- await svc.onModuleInit();
532
- return svc;
533
- },
534
- inject: [import_runtime7.OPENAPI_RUNTIME_OPTIONS]
533
+ provide: OPENAPI_VALIDATOR_RUNTIME,
534
+ useFactory: async (opts) => import_runtime7.OpenAPIRuntimePool.getOrCreate({ specSource: opts.specSource, debug: opts.debug }),
535
+ inject: [OPENAPI_VALIDATOR_OPTIONS]
535
536
  },
536
- OpenApiValidatorService,
537
- { provide: OPENAPI_VALIDATOR, useExisting: OpenApiValidatorService },
537
+ OpenAPIValidatorService,
538
+ { provide: OPENAPI_VALIDATOR, useExisting: OpenAPIValidatorService },
538
539
  // Interceptors
539
540
  { provide: import_core3.APP_INTERCEPTOR, useClass: RequestValidationInterceptor }
540
541
  ];
@@ -545,13 +546,11 @@ var OpenApiValidatorModule = class {
545
546
  });
546
547
  }
547
548
  return {
548
- module: OpenApiValidatorModule,
549
+ module: OpenAPIValidatorModule,
549
550
  providers,
550
551
  exports: [
551
- OPENAPI_VALIDATOR_OPTIONS,
552
552
  OPENAPI_VALIDATOR,
553
- import_runtime7.OpenApiRuntimeService,
554
- OpenApiValidatorService
553
+ OpenAPIValidatorService
555
554
  ]
556
555
  };
557
556
  }
@@ -586,16 +585,12 @@ var OpenApiValidatorModule = class {
586
585
  },
587
586
  // Core services
588
587
  {
589
- provide: import_runtime7.OpenApiRuntimeService,
590
- useFactory: async (runtimeOptions) => {
591
- const svc = new import_runtime7.OpenApiRuntimeService(runtimeOptions);
592
- await svc.onModuleInit();
593
- return svc;
594
- },
595
- inject: [import_runtime7.OPENAPI_RUNTIME_OPTIONS]
588
+ provide: OPENAPI_VALIDATOR_RUNTIME,
589
+ useFactory: async (opts) => import_runtime7.OpenAPIRuntimePool.getOrCreate({ specSource: opts.specSource, debug: opts.debug }),
590
+ inject: [OPENAPI_VALIDATOR_OPTIONS]
596
591
  },
597
- OpenApiValidatorService,
598
- { provide: OPENAPI_VALIDATOR, useExisting: OpenApiValidatorService },
592
+ OpenAPIValidatorService,
593
+ { provide: OPENAPI_VALIDATOR, useExisting: OpenAPIValidatorService },
599
594
  // Interceptors
600
595
  { provide: import_core3.APP_INTERCEPTOR, useClass: RequestValidationInterceptor },
601
596
  // Conditionally add response validation
@@ -607,30 +602,28 @@ var OpenApiValidatorModule = class {
607
602
  }
608
603
  return { intercept: (_ctx, next) => next.handle() };
609
604
  },
610
- inject: [OPENAPI_VALIDATOR_OPTIONS, OpenApiValidatorService, import_core3.Reflector]
605
+ inject: [OPENAPI_VALIDATOR_OPTIONS, OpenAPIValidatorService, import_core3.Reflector]
611
606
  }
612
607
  ];
613
608
  return {
614
- module: OpenApiValidatorModule,
609
+ module: OpenAPIValidatorModule,
615
610
  imports: options.imports || [],
616
611
  providers,
617
612
  exports: [
618
- OPENAPI_VALIDATOR_OPTIONS,
619
613
  OPENAPI_VALIDATOR,
620
- import_runtime7.OpenApiRuntimeService,
621
- OpenApiValidatorService
614
+ OpenAPIValidatorService
622
615
  ]
623
616
  };
624
617
  }
625
618
  };
626
- OpenApiValidatorModule = __decorateClass([
619
+ OpenAPIValidatorModule = __decorateClass([
627
620
  (0, import_common5.Global)(),
628
621
  (0, import_common5.Module)({})
629
- ], OpenApiValidatorModule);
622
+ ], OpenAPIValidatorModule);
630
623
  // Annotate the CommonJS export names for ESM import in node:
631
624
  0 && (module.exports = {
632
625
  OPENAPI_VALIDATOR,
633
- OpenApiValidatorModule,
634
- OpenApiValidatorService,
626
+ OpenAPIValidatorModule,
627
+ OpenAPIValidatorService,
635
628
  Validate
636
629
  });
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { ExecutionContext, DynamicModule, OnApplicationBootstrap } from '@nestjs/common';
3
3
  import Ajv, { ErrorObject, Options } from 'ajv';
4
- import { SpecSource, OpenAPISpec, OpenApiRuntimeService } from '@nest-openapi/runtime';
4
+ import { SpecSource, OpenAPISpec, OpenAPIRuntimeService } from '@nest-openapi/runtime';
5
5
  import { HttpArgumentsHost } from '@nestjs/common/interfaces';
6
6
 
7
7
  interface ValidationError extends ErrorObject {
@@ -88,7 +88,7 @@ interface ValidatorOptions {
88
88
  debug?: boolean;
89
89
  }
90
90
 
91
- declare class OpenApiValidatorModule {
91
+ declare class OpenAPIValidatorModule {
92
92
  /**
93
93
  * Configure the OpenAPI validator module with static options
94
94
  */
@@ -103,15 +103,15 @@ declare class OpenApiValidatorModule {
103
103
  }): DynamicModule;
104
104
  }
105
105
 
106
- declare const OPENAPI_VALIDATOR = "OPENAPI_VALIDATOR";
107
- declare class OpenApiValidatorService implements OnApplicationBootstrap {
106
+ declare const OPENAPI_VALIDATOR: unique symbol;
107
+ declare class OpenAPIValidatorService implements OnApplicationBootstrap {
108
108
  private readonly runtime;
109
109
  private readonly options;
110
110
  private readonly logger;
111
111
  private ajv;
112
112
  openApiSpec: OpenAPISpec;
113
113
  private debugLog;
114
- constructor(runtime: OpenApiRuntimeService, options: ValidatorOptions);
114
+ constructor(runtime: OpenAPIRuntimeService, options: ValidatorOptions);
115
115
  onApplicationBootstrap(): Promise<void>;
116
116
  private get isSpecLoaded();
117
117
  get validationOptions(): ValidatorOptions;
@@ -137,7 +137,8 @@ declare class OpenApiValidatorService implements OnApplicationBootstrap {
137
137
  private getParameterSchema;
138
138
  }
139
139
 
140
- interface ValidateOptions {
140
+ declare const VALIDATE_OVERRIDE: unique symbol;
141
+ interface ValidateOverrideOptions {
141
142
  request?: boolean | {
142
143
  params?: boolean;
143
144
  query?: boolean;
@@ -173,6 +174,6 @@ interface ValidateOptions {
173
174
  * }
174
175
  * ```
175
176
  */
176
- declare const Validate: (options?: ValidateOptions) => _nestjs_common.CustomDecorator<string>;
177
+ declare const Validate: (options?: ValidateOverrideOptions) => _nestjs_common.CustomDecorator<typeof VALIDATE_OVERRIDE>;
177
178
 
178
- export { OPENAPI_VALIDATOR, OpenApiValidatorModule, OpenApiValidatorService, Validate, type ValidateOptions, type ValidationError, type ValidationErrorResponse, type ValidatorOptions };
179
+ export { OPENAPI_VALIDATOR, OpenAPIValidatorModule, OpenAPIValidatorService, Validate, type ValidateOverrideOptions, type ValidationError, type ValidationErrorResponse, type ValidatorOptions };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { ExecutionContext, DynamicModule, OnApplicationBootstrap } from '@nestjs/common';
3
3
  import Ajv, { ErrorObject, Options } from 'ajv';
4
- import { SpecSource, OpenAPISpec, OpenApiRuntimeService } from '@nest-openapi/runtime';
4
+ import { SpecSource, OpenAPISpec, OpenAPIRuntimeService } from '@nest-openapi/runtime';
5
5
  import { HttpArgumentsHost } from '@nestjs/common/interfaces';
6
6
 
7
7
  interface ValidationError extends ErrorObject {
@@ -88,7 +88,7 @@ interface ValidatorOptions {
88
88
  debug?: boolean;
89
89
  }
90
90
 
91
- declare class OpenApiValidatorModule {
91
+ declare class OpenAPIValidatorModule {
92
92
  /**
93
93
  * Configure the OpenAPI validator module with static options
94
94
  */
@@ -103,15 +103,15 @@ declare class OpenApiValidatorModule {
103
103
  }): DynamicModule;
104
104
  }
105
105
 
106
- declare const OPENAPI_VALIDATOR = "OPENAPI_VALIDATOR";
107
- declare class OpenApiValidatorService implements OnApplicationBootstrap {
106
+ declare const OPENAPI_VALIDATOR: unique symbol;
107
+ declare class OpenAPIValidatorService implements OnApplicationBootstrap {
108
108
  private readonly runtime;
109
109
  private readonly options;
110
110
  private readonly logger;
111
111
  private ajv;
112
112
  openApiSpec: OpenAPISpec;
113
113
  private debugLog;
114
- constructor(runtime: OpenApiRuntimeService, options: ValidatorOptions);
114
+ constructor(runtime: OpenAPIRuntimeService, options: ValidatorOptions);
115
115
  onApplicationBootstrap(): Promise<void>;
116
116
  private get isSpecLoaded();
117
117
  get validationOptions(): ValidatorOptions;
@@ -137,7 +137,8 @@ declare class OpenApiValidatorService implements OnApplicationBootstrap {
137
137
  private getParameterSchema;
138
138
  }
139
139
 
140
- interface ValidateOptions {
140
+ declare const VALIDATE_OVERRIDE: unique symbol;
141
+ interface ValidateOverrideOptions {
141
142
  request?: boolean | {
142
143
  params?: boolean;
143
144
  query?: boolean;
@@ -173,6 +174,6 @@ interface ValidateOptions {
173
174
  * }
174
175
  * ```
175
176
  */
176
- declare const Validate: (options?: ValidateOptions) => _nestjs_common.CustomDecorator<string>;
177
+ declare const Validate: (options?: ValidateOverrideOptions) => _nestjs_common.CustomDecorator<typeof VALIDATE_OVERRIDE>;
177
178
 
178
- export { OPENAPI_VALIDATOR, OpenApiValidatorModule, OpenApiValidatorService, Validate, type ValidateOptions, type ValidationError, type ValidationErrorResponse, type ValidatorOptions };
179
+ export { OPENAPI_VALIDATOR, OpenAPIValidatorModule, OpenAPIValidatorService, Validate, type ValidateOverrideOptions, type ValidationError, type ValidationErrorResponse, type ValidatorOptions };
package/dist/index.js CHANGED
@@ -16,11 +16,16 @@ import { APP_INTERCEPTOR, Reflector as Reflector3 } from "@nestjs/core";
16
16
 
17
17
  // src/services/openapi-validator.service.ts
18
18
  import { Injectable, Logger, Inject } from "@nestjs/common";
19
- import { OpenApiRuntimeService, DebugUtil, PlatformUtil } from "@nest-openapi/runtime";
19
+ import { DebugUtil, PlatformUtil } from "@nest-openapi/runtime";
20
20
  import Ajv from "ajv";
21
- var OPENAPI_VALIDATOR_OPTIONS = "OPENAPI_VALIDATOR_OPTIONS";
22
- var OPENAPI_VALIDATOR = "OPENAPI_VALIDATOR";
23
- var OpenApiValidatorService = class {
21
+
22
+ // src/types/validator-options.interface.ts
23
+ var OPENAPI_VALIDATOR_RUNTIME = Symbol("OPENAPI_VALIDATOR_RUNTIME");
24
+ var OPENAPI_VALIDATOR_OPTIONS = Symbol("OPENAPI_VALIDATOR_OPTIONS");
25
+
26
+ // src/services/openapi-validator.service.ts
27
+ var OPENAPI_VALIDATOR = Symbol("OPENAPI_VALIDATOR");
28
+ var OpenAPIValidatorService = class {
24
29
  constructor(runtime, options) {
25
30
  this.runtime = runtime;
26
31
  this.options = options;
@@ -42,7 +47,7 @@ var OpenApiValidatorService = class {
42
47
  ${JSON.stringify(opts, null, 2)}`);
43
48
  }
44
49
  }
45
- logger = new Logger("OpenApiValidator");
50
+ logger = new Logger("OpenAPIValidator");
46
51
  ajv;
47
52
  openApiSpec;
48
53
  debugLog;
@@ -301,11 +306,11 @@ ${JSON.stringify(data, null, 2)}`);
301
306
  };
302
307
  }
303
308
  };
304
- OpenApiValidatorService = __decorateClass([
309
+ OpenAPIValidatorService = __decorateClass([
305
310
  Injectable(),
306
- __decorateParam(0, Inject(OpenApiRuntimeService)),
311
+ __decorateParam(0, Inject(OPENAPI_VALIDATOR_RUNTIME)),
307
312
  __decorateParam(1, Inject(OPENAPI_VALIDATOR_OPTIONS))
308
- ], OpenApiValidatorService);
313
+ ], OpenAPIValidatorService);
309
314
 
310
315
  // src/interceptors/request-validation.interceptor.ts
311
316
  import {
@@ -319,8 +324,8 @@ import { DebugUtil as DebugUtil2 } from "@nest-openapi/runtime";
319
324
 
320
325
  // src/decorators/validate.decorator.ts
321
326
  import { SetMetadata } from "@nestjs/common";
322
- var VALIDATE_KEY = "VALIDATE";
323
- var Validate = (options = {}) => SetMetadata(VALIDATE_KEY, options);
327
+ var VALIDATE_OVERRIDE = Symbol("VALIDATE_OVERRIDE");
328
+ var Validate = (options = {}) => SetMetadata(VALIDATE_OVERRIDE, options);
324
329
 
325
330
  // src/interceptors/request-validation.interceptor.ts
326
331
  var RequestValidationInterceptor = class {
@@ -329,7 +334,7 @@ var RequestValidationInterceptor = class {
329
334
  this.reflector = reflector;
330
335
  this.debugLog = DebugUtil2.createDebugFn(this.logger, this.validatorService.validationOptions.debug || false);
331
336
  }
332
- logger = new Logger2("OpenApiValidator");
337
+ logger = new Logger2("OpenAPIValidator");
333
338
  debugLog;
334
339
  async intercept(context, next) {
335
340
  if (!this.validatorService.openApiSpec) {
@@ -363,7 +368,7 @@ var RequestValidationInterceptor = class {
363
368
  }
364
369
  getValidationDecorator(context) {
365
370
  const validateMetadata = this.reflector.getAllAndOverride(
366
- VALIDATE_KEY,
371
+ VALIDATE_OVERRIDE,
367
372
  [context.getHandler(), context.getClass()]
368
373
  );
369
374
  if (validateMetadata) {
@@ -411,7 +416,7 @@ var ResponseValidationInterceptor = class {
411
416
  this.reflector = reflector;
412
417
  this.debugLog = DebugUtil3.createDebugFn(this.logger, this.validatorService.validationOptions.debug || false);
413
418
  }
414
- logger = new Logger3("OpenApiValidator");
419
+ logger = new Logger3("OpenAPIValidator");
415
420
  debugLog;
416
421
  intercept(context, next) {
417
422
  if (!this.validatorService.openApiSpec) {
@@ -451,7 +456,7 @@ var ResponseValidationInterceptor = class {
451
456
  }
452
457
  shouldValidateResponse(context) {
453
458
  const validateMetadata = this.reflector.getAllAndOverride(
454
- VALIDATE_KEY,
459
+ VALIDATE_OVERRIDE,
455
460
  [context.getHandler(), context.getClass()]
456
461
  );
457
462
  if (validateMetadata) {
@@ -474,8 +479,8 @@ ResponseValidationInterceptor = __decorateClass([
474
479
  ], ResponseValidationInterceptor);
475
480
 
476
481
  // src/modules/openapi-validator.module.ts
477
- import { OpenApiRuntimeService as OpenApiRuntimeService2, OPENAPI_RUNTIME_OPTIONS } from "@nest-openapi/runtime";
478
- var OpenApiValidatorModule = class {
482
+ import { OPENAPI_RUNTIME_OPTIONS, OpenAPIRuntimePool } from "@nest-openapi/runtime";
483
+ var OpenAPIValidatorModule = class {
479
484
  /**
480
485
  * Configure the OpenAPI validator module with static options
481
486
  */
@@ -499,16 +504,12 @@ var OpenApiValidatorModule = class {
499
504
  },
500
505
  // Core services
501
506
  {
502
- provide: OpenApiRuntimeService2,
503
- useFactory: async (runtimeOptions) => {
504
- const svc = new OpenApiRuntimeService2(runtimeOptions);
505
- await svc.onModuleInit();
506
- return svc;
507
- },
508
- inject: [OPENAPI_RUNTIME_OPTIONS]
507
+ provide: OPENAPI_VALIDATOR_RUNTIME,
508
+ useFactory: async (opts) => OpenAPIRuntimePool.getOrCreate({ specSource: opts.specSource, debug: opts.debug }),
509
+ inject: [OPENAPI_VALIDATOR_OPTIONS]
509
510
  },
510
- OpenApiValidatorService,
511
- { provide: OPENAPI_VALIDATOR, useExisting: OpenApiValidatorService },
511
+ OpenAPIValidatorService,
512
+ { provide: OPENAPI_VALIDATOR, useExisting: OpenAPIValidatorService },
512
513
  // Interceptors
513
514
  { provide: APP_INTERCEPTOR, useClass: RequestValidationInterceptor }
514
515
  ];
@@ -519,13 +520,11 @@ var OpenApiValidatorModule = class {
519
520
  });
520
521
  }
521
522
  return {
522
- module: OpenApiValidatorModule,
523
+ module: OpenAPIValidatorModule,
523
524
  providers,
524
525
  exports: [
525
- OPENAPI_VALIDATOR_OPTIONS,
526
526
  OPENAPI_VALIDATOR,
527
- OpenApiRuntimeService2,
528
- OpenApiValidatorService
527
+ OpenAPIValidatorService
529
528
  ]
530
529
  };
531
530
  }
@@ -560,16 +559,12 @@ var OpenApiValidatorModule = class {
560
559
  },
561
560
  // Core services
562
561
  {
563
- provide: OpenApiRuntimeService2,
564
- useFactory: async (runtimeOptions) => {
565
- const svc = new OpenApiRuntimeService2(runtimeOptions);
566
- await svc.onModuleInit();
567
- return svc;
568
- },
569
- inject: [OPENAPI_RUNTIME_OPTIONS]
562
+ provide: OPENAPI_VALIDATOR_RUNTIME,
563
+ useFactory: async (opts) => OpenAPIRuntimePool.getOrCreate({ specSource: opts.specSource, debug: opts.debug }),
564
+ inject: [OPENAPI_VALIDATOR_OPTIONS]
570
565
  },
571
- OpenApiValidatorService,
572
- { provide: OPENAPI_VALIDATOR, useExisting: OpenApiValidatorService },
566
+ OpenAPIValidatorService,
567
+ { provide: OPENAPI_VALIDATOR, useExisting: OpenAPIValidatorService },
573
568
  // Interceptors
574
569
  { provide: APP_INTERCEPTOR, useClass: RequestValidationInterceptor },
575
570
  // Conditionally add response validation
@@ -581,29 +576,27 @@ var OpenApiValidatorModule = class {
581
576
  }
582
577
  return { intercept: (_ctx, next) => next.handle() };
583
578
  },
584
- inject: [OPENAPI_VALIDATOR_OPTIONS, OpenApiValidatorService, Reflector3]
579
+ inject: [OPENAPI_VALIDATOR_OPTIONS, OpenAPIValidatorService, Reflector3]
585
580
  }
586
581
  ];
587
582
  return {
588
- module: OpenApiValidatorModule,
583
+ module: OpenAPIValidatorModule,
589
584
  imports: options.imports || [],
590
585
  providers,
591
586
  exports: [
592
- OPENAPI_VALIDATOR_OPTIONS,
593
587
  OPENAPI_VALIDATOR,
594
- OpenApiRuntimeService2,
595
- OpenApiValidatorService
588
+ OpenAPIValidatorService
596
589
  ]
597
590
  };
598
591
  }
599
592
  };
600
- OpenApiValidatorModule = __decorateClass([
593
+ OpenAPIValidatorModule = __decorateClass([
601
594
  Global(),
602
595
  Module({})
603
- ], OpenApiValidatorModule);
596
+ ], OpenAPIValidatorModule);
604
597
  export {
605
598
  OPENAPI_VALIDATOR,
606
- OpenApiValidatorModule,
607
- OpenApiValidatorService,
599
+ OpenAPIValidatorModule,
600
+ OpenAPIValidatorService,
608
601
  Validate
609
602
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nest-openapi/validator",
3
- "version": "0.1.0",
4
- "description": "Automatic request/response validation for NestJS using OpenAPI specifications",
3
+ "version": "0.1.1",
4
+ "description": "Automatic request/response validation for NestJS using your OpenAPI specifications",
5
5
  "sideEffects": false,
6
6
  "keywords": [
7
7
  "nest",
@@ -27,6 +27,16 @@
27
27
  "README.md",
28
28
  "LICENSE"
29
29
  ],
30
+ "scripts": {
31
+ "build": "tsup src/index.ts --format esm,cjs --dts --target node20 --outDir dist --clean --external rxjs --external ajv --external @nestjs/common --external @nestjs/core",
32
+ "test": "jest",
33
+ "test:watch": "jest --watch",
34
+ "test:cov": "jest --coverage",
35
+ "prepack": "node -e \"const fs=require('fs');const path=require('path');fs.copyFileSync(path.resolve(__dirname,'..','..','README.md'), path.resolve(__dirname,'README.md'));\"",
36
+ "postpack": "node -e \"const fs=require('fs');const path=require('path');try{fs.unlinkSync(path.resolve(__dirname,'README.md'))}catch(_){}\"",
37
+ "lint": "eslint .",
38
+ "lint:fix": "eslint . --fix"
39
+ },
30
40
  "homepage": "https://nest-openapi.github.io/",
31
41
  "repository": {
32
42
  "type": "git",
@@ -44,7 +54,7 @@
44
54
  "@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0",
45
55
  "@nestjs/core": "^9.0.0 || ^10.0.0 || ^11.0.0",
46
56
  "ajv": "^8.0.0",
47
- "reflect-metadata": "^0.1.13"
57
+ "reflect-metadata": "^0.2.2"
48
58
  },
49
59
  "peerDependenciesMeta": {
50
60
  "ajv": {
@@ -52,10 +62,12 @@
52
62
  }
53
63
  },
54
64
  "dependencies": {
55
- "@nest-openapi/runtime": "^0.1.0",
56
- "ajv": "^8.0.0"
65
+ "@nest-openapi/runtime": "^0.1.1",
66
+ "ajv": "^8.0.0",
67
+ "rxjs": "^7.2.0"
57
68
  },
58
69
  "devDependencies": {
70
+ "@nest-openapi/runtime": "workspace:^",
59
71
  "@nestjs/common": "^11.0.0",
60
72
  "@nestjs/core": "^11.0.0",
61
73
  "@nestjs/platform-express": "^11.1.3",
@@ -66,13 +78,11 @@
66
78
  "@typescript-eslint/parser": "^8.35.1",
67
79
  "eslint": "^9.30.1",
68
80
  "jest": "^29.0.0",
69
- "reflect-metadata": "^0.1.13",
70
- "rxjs": "^7.2.0",
81
+ "reflect-metadata": "^0.2.2",
71
82
  "supertest": "^7.1.0",
72
83
  "ts-jest": "^29.0.0",
73
84
  "tsup": "^8.5.0",
74
- "typescript": "^5.0.0",
75
- "@nest-openapi/runtime": "^0.1.0"
85
+ "typescript": "^5.9.0"
76
86
  },
77
87
  "jest": {
78
88
  "moduleFileExtensions": [
@@ -91,13 +101,5 @@
91
101
  ],
92
102
  "coverageDirectory": "coverage",
93
103
  "testEnvironment": "node"
94
- },
95
- "scripts": {
96
- "build": "tsup src/index.ts --format esm,cjs --dts --target node20 --outDir dist --clean --external rxjs --external ajv --external @nestjs/common --external @nestjs/core",
97
- "test": "jest",
98
- "test:watch": "jest --watch",
99
- "test:cov": "jest --coverage",
100
- "lint": "eslint .",
101
- "lint:fix": "eslint . --fix"
102
104
  }
103
- }
105
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 nest-openapi
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.