@camcima/nestjs-rfc9457 0.0.2 → 0.2.0
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 +231 -9
- package/dist/swagger/apply-problem-detail-responses.d.ts +6 -0
- package/dist/swagger/apply-problem-detail-responses.js +66 -0
- package/dist/swagger/apply-problem-detail-responses.js.map +1 -0
- package/dist/swagger/index.d.ts +2 -0
- package/dist/swagger/index.js +10 -0
- package/dist/swagger/index.js.map +1 -0
- package/dist/swagger/problem-detail.dto.d.ts +15 -0
- package/dist/swagger/problem-detail.dto.js +87 -0
- package/dist/swagger/problem-detail.dto.js.map +1 -0
- package/package.json +32 -14
package/README.md
CHANGED
|
@@ -7,17 +7,36 @@
|
|
|
7
7
|
<br>
|
|
8
8
|
|
|
9
9
|
[](https://github.com/camcima/nestjs-rfc9457/actions/workflows/ci.yml)
|
|
10
|
+
[](https://github.com/camcima/nestjs-rfc9457/actions/workflows/codeql.yml)
|
|
10
11
|
[](https://codecov.io/gh/camcima/nestjs-rfc9457)
|
|
11
12
|
[](https://www.npmjs.com/package/@camcima/nestjs-rfc9457)
|
|
12
|
-
[](https://www.npmjs.com/package/@camcima/nestjs-rfc9457)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
14
|
-
[](https://www.typescriptlang.org/)
|
|
15
15
|
[](https://nodejs.org/)
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
19
|
NestJS library for [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) Problem Details HTTP error responses.
|
|
20
20
|
|
|
21
|
+
## Table of Contents
|
|
22
|
+
|
|
23
|
+
- [What is RFC 9457?](#what-is-rfc-9457)
|
|
24
|
+
- [Features](#features)
|
|
25
|
+
- [Installation](#installation)
|
|
26
|
+
- [Quick Start](#quick-start)
|
|
27
|
+
- [Configuration](#configuration)
|
|
28
|
+
- [Async Configuration](#async-configuration)
|
|
29
|
+
- [Custom Exception Types](#custom-exception-types)
|
|
30
|
+
- [Validation Integration](#validation-integration)
|
|
31
|
+
- [Swagger / OpenAPI Integration](#swagger--openapi-integration)
|
|
32
|
+
- [Advanced Usage](#advanced-usage)
|
|
33
|
+
- [API Reference](#api-reference)
|
|
34
|
+
- [Example Responses](#example-responses)
|
|
35
|
+
- [Examples](#examples)
|
|
36
|
+
- [Security](#security)
|
|
37
|
+
- [Contributing](#contributing)
|
|
38
|
+
- [License](#license)
|
|
39
|
+
|
|
21
40
|
## What is RFC 9457?
|
|
22
41
|
|
|
23
42
|
[RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (July 2023) defines a standard JSON format for HTTP API error responses, using the `application/problem+json` media type. It supersedes RFC 7807 and gives APIs a consistent, machine-readable way to communicate errors.
|
|
@@ -59,8 +78,9 @@ Extension members (arbitrary key-value pairs) are allowed for problem-type-speci
|
|
|
59
78
|
- Optional catch-all mode for non-`HttpException` throwables (produces 500 Problem Details)
|
|
60
79
|
- Custom `exceptionMapper` callback for full control over any exception
|
|
61
80
|
- `ProblemDetailsFactory` is injectable — use it directly in GraphQL, microservices, or custom filters
|
|
81
|
+
- Optional `@nestjs/swagger` integration: `ProblemDetailDto` and `ValidationProblemDetailDto` for OpenAPI documentation, plus a `applyProblemDetailResponses()` helper that auto-applies `@ApiResponse` decorators to all controllers under `application/problem+json`
|
|
62
82
|
- Works with both Express and Fastify adapters
|
|
63
|
-
- Zero runtime dependencies; `class-validator`
|
|
83
|
+
- Zero runtime dependencies; `class-validator` and `@nestjs/swagger` are optional peer dependencies
|
|
64
84
|
|
|
65
85
|
---
|
|
66
86
|
|
|
@@ -80,12 +100,13 @@ pnpm add @camcima/nestjs-rfc9457
|
|
|
80
100
|
|
|
81
101
|
### Peer dependencies
|
|
82
102
|
|
|
83
|
-
| Package | Version
|
|
84
|
-
| ------------------ |
|
|
85
|
-
| `@nestjs/common` | `^10.0.0 \|\| ^11.0.0`
|
|
86
|
-
| `@nestjs/core` | `^10.0.0 \|\| ^11.0.0`
|
|
87
|
-
| `reflect-metadata` | `^0.1.13 \|\| ^0.2.0`
|
|
88
|
-
| `class-validator` | `^0.14.0`
|
|
103
|
+
| Package | Version | Required |
|
|
104
|
+
| ------------------ | --------------------------------- | -------------------------------------- |
|
|
105
|
+
| `@nestjs/common` | `^10.0.0 \|\| ^11.0.0` | Yes |
|
|
106
|
+
| `@nestjs/core` | `^10.0.0 \|\| ^11.0.0` | Yes |
|
|
107
|
+
| `reflect-metadata` | `^0.1.13 \|\| ^0.2.0` | Yes |
|
|
108
|
+
| `class-validator` | `^0.14.0` | No (optional, for Tier 2 validation) |
|
|
109
|
+
| `@nestjs/swagger` | `^7.0.0 \|\| ^8.0.0 \|\| ^11.0.0` | No (optional, for OpenAPI integration) |
|
|
89
110
|
|
|
90
111
|
---
|
|
91
112
|
|
|
@@ -522,6 +543,156 @@ Nested validation errors are preserved as `children` arrays matching the `class-
|
|
|
522
543
|
|
|
523
544
|
---
|
|
524
545
|
|
|
546
|
+
## Swagger / OpenAPI Integration
|
|
547
|
+
|
|
548
|
+
The library ships optional Swagger support under a separate import path so it does not require `@nestjs/swagger` as a mandatory dependency. Install `@nestjs/swagger` as usual if you have not already:
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
npm install @nestjs/swagger
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
All Swagger-related exports are imported from the `/swagger` subpath:
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
import {
|
|
558
|
+
ProblemDetailDto,
|
|
559
|
+
ValidationProblemDetailDto,
|
|
560
|
+
ValidationErrorDto,
|
|
561
|
+
applyProblemDetailResponses,
|
|
562
|
+
} from '@camcima/nestjs-rfc9457/swagger';
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Auto-applying error schemas to all controllers
|
|
566
|
+
|
|
567
|
+
The `applyProblemDetailResponses()` helper uses NestJS's `DiscoveryService` to programmatically attach `@ApiResponse` decorators to every controller in your application. Responses are documented under `application/problem+json` as required by RFC 9457.
|
|
568
|
+
|
|
569
|
+
**Step 1** — Import `DiscoveryModule` in your app module:
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
import { Module } from '@nestjs/common';
|
|
573
|
+
import { DiscoveryModule } from '@nestjs/core';
|
|
574
|
+
import { Rfc9457Module } from '@camcima/nestjs-rfc9457';
|
|
575
|
+
|
|
576
|
+
@Module({
|
|
577
|
+
imports: [DiscoveryModule, Rfc9457Module.forRoot()],
|
|
578
|
+
})
|
|
579
|
+
export class AppModule {}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
**Step 2** — Call the helper inside the lazy document factory passed to `SwaggerModule.setup()`:
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
586
|
+
import { applyProblemDetailResponses } from '@camcima/nestjs-rfc9457/swagger';
|
|
587
|
+
|
|
588
|
+
const config = new DocumentBuilder().setTitle('My API').build();
|
|
589
|
+
|
|
590
|
+
SwaggerModule.setup('/api', app, () => {
|
|
591
|
+
applyProblemDetailResponses(app);
|
|
592
|
+
return SwaggerModule.createDocument(app, config);
|
|
593
|
+
});
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
By default, this documents `400` and `500` responses on every route using `ProblemDetailDto`. The generated OpenAPI spec will show `application/problem+json` as the response media type with the correct schema.
|
|
597
|
+
|
|
598
|
+
### Options
|
|
599
|
+
|
|
600
|
+
`applyProblemDetailResponses` accepts an optional second argument:
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
interface ApplyProblemDetailResponsesOptions {
|
|
604
|
+
/** HTTP status codes to document. Default: [400, 500]. */
|
|
605
|
+
statuses?: number[];
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Statuses that use ValidationProblemDetailDto (with the errors array)
|
|
609
|
+
* instead of the base ProblemDetailDto. Default: [].
|
|
610
|
+
*/
|
|
611
|
+
validationStatuses?: number[];
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
#### Documenting additional statuses
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
applyProblemDetailResponses(app, {
|
|
619
|
+
statuses: [400, 401, 403, 404, 500],
|
|
620
|
+
});
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
#### Documenting Tier 2 structured validation errors
|
|
624
|
+
|
|
625
|
+
If you use `Rfc9457ValidationException` (Tier 2) for validation, you can tell the helper to use `ValidationProblemDetailDto` for specific statuses. This DTO includes the `errors` array of structured `ValidationErrorDto` objects:
|
|
626
|
+
|
|
627
|
+
```typescript
|
|
628
|
+
applyProblemDetailResponses(app, {
|
|
629
|
+
statuses: [400, 500],
|
|
630
|
+
validationStatuses: [400],
|
|
631
|
+
});
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
This documents 400 responses with the `ValidationProblemDetailDto` schema (which includes `errors: ValidationErrorDto[]`) and 500 responses with the base `ProblemDetailDto`.
|
|
635
|
+
|
|
636
|
+
### Using DTOs manually for per-route documentation
|
|
637
|
+
|
|
638
|
+
For finer control, use the DTO classes directly with `@ApiResponse()` on individual routes:
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
import { ApiResponse } from '@nestjs/swagger';
|
|
642
|
+
import { ProblemDetailDto, ValidationProblemDetailDto } from '@camcima/nestjs-rfc9457/swagger';
|
|
643
|
+
|
|
644
|
+
@Get(':id')
|
|
645
|
+
@ApiResponse({
|
|
646
|
+
status: 404,
|
|
647
|
+
description: 'Not Found',
|
|
648
|
+
content: {
|
|
649
|
+
'application/problem+json': {
|
|
650
|
+
schema: { $ref: '#/components/schemas/ProblemDetailDto' },
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
})
|
|
654
|
+
findOne(@Param('id') id: string) {
|
|
655
|
+
// ...
|
|
656
|
+
}
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
Or more concisely using the `type` shorthand (documents as `application/json` instead of `application/problem+json`):
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
@ApiResponse({ status: 404, type: ProblemDetailDto })
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Extending DTOs for custom extension members
|
|
666
|
+
|
|
667
|
+
If your API returns extension members (additional fields beyond the five standard RFC 9457 members), extend `ProblemDetailDto` to document them:
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
671
|
+
import { ProblemDetailDto } from '@camcima/nestjs-rfc9457/swagger';
|
|
672
|
+
|
|
673
|
+
export class InsufficientFundsProblemDto extends ProblemDetailDto {
|
|
674
|
+
@ApiProperty({ example: 50 })
|
|
675
|
+
balance!: number;
|
|
676
|
+
|
|
677
|
+
@ApiProperty({ example: 100 })
|
|
678
|
+
required!: number;
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
### Available DTOs
|
|
683
|
+
|
|
684
|
+
| DTO | Description |
|
|
685
|
+
| ---------------------------- | ------------------------------------------------------------------------------------ |
|
|
686
|
+
| `ProblemDetailDto` | The five standard RFC 9457 fields (`type`, `title`, `status`, `detail`, `instance`) |
|
|
687
|
+
| `ValidationProblemDetailDto` | Extends `ProblemDetailDto` with `errors: ValidationErrorDto[]` for Tier 2 validation |
|
|
688
|
+
| `ValidationErrorDto` | Structured validation error (`property`, `constraints?`, `children?`) |
|
|
689
|
+
|
|
690
|
+
### Design note
|
|
691
|
+
|
|
692
|
+
The auto-apply helper uses `ProblemDetailDto` for all statuses by default. This is intentional: a single HTTP status (e.g. 400) can produce different response shapes at runtime — a plain problem detail for non-validation errors, `errors: string[]` for Tier 1 validation, or `errors: ValidationErrorDto[]` for Tier 2 validation. The base DTO is the common denominator that is always correct. Use `validationStatuses` to opt in to the more specific schema when your application uses Tier 2 validation exclusively.
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
525
696
|
## Advanced Usage
|
|
526
697
|
|
|
527
698
|
### Using `ProblemDetailsFactory` directly
|
|
@@ -606,6 +777,16 @@ export class MySpecialExceptionFilter extends BaseExceptionFilter {
|
|
|
606
777
|
| `RFC9457_MODULE_OPTIONS` | Symbol | DI token for the module options |
|
|
607
778
|
| `PROBLEM_CONTENT_TYPE` | Constant | `'application/problem+json'` |
|
|
608
779
|
|
|
780
|
+
**Swagger subpath** (`@camcima/nestjs-rfc9457/swagger`):
|
|
781
|
+
|
|
782
|
+
| Export | Kind | Description |
|
|
783
|
+
| ------------------------------------ | --------- | ------------------------------------------------------------------------------------- |
|
|
784
|
+
| `ProblemDetailDto` | Class | Swagger DTO for the five standard RFC 9457 fields |
|
|
785
|
+
| `ValidationProblemDetailDto` | Class | Extends `ProblemDetailDto` with `errors: ValidationErrorDto[]` |
|
|
786
|
+
| `ValidationErrorDto` | Class | Swagger DTO for a structured validation error (`property`, `constraints`, `children`) |
|
|
787
|
+
| `applyProblemDetailResponses` | Function | Auto-applies `@ApiResponse` decorators to all controllers via `DiscoveryService` |
|
|
788
|
+
| `ApplyProblemDetailResponsesOptions` | Interface | Options for `applyProblemDetailResponses` |
|
|
789
|
+
|
|
609
790
|
---
|
|
610
791
|
|
|
611
792
|
## Example Responses
|
|
@@ -719,6 +900,47 @@ Internal error messages are never included in the response to avoid leaking sens
|
|
|
719
900
|
|
|
720
901
|
---
|
|
721
902
|
|
|
903
|
+
## Examples
|
|
904
|
+
|
|
905
|
+
See the [nestjs-rfc9457-examples](https://github.com/camcima/nestjs-rfc9457-examples) repository for complete working NestJS applications demonstrating all features, including runnable demo scripts.
|
|
906
|
+
|
|
907
|
+
---
|
|
908
|
+
|
|
909
|
+
## Security
|
|
910
|
+
|
|
911
|
+
### CI
|
|
912
|
+
|
|
913
|
+
| Tool | Purpose | Trigger |
|
|
914
|
+
| --------------- | -------------------------------------------------------- | ------------------------- |
|
|
915
|
+
| **CodeQL** | Static analysis for security vulnerabilities | Push, PR, weekly schedule |
|
|
916
|
+
| **OSV-Scanner** | Dependency vulnerability scanning (production deps only) | Push, PR |
|
|
917
|
+
| **Dependabot** | Automated dependency and GitHub Actions updates | Weekly PRs |
|
|
918
|
+
| **Codecov** | Test coverage tracking | Push, PR |
|
|
919
|
+
|
|
920
|
+
### Local (via Lefthook)
|
|
921
|
+
|
|
922
|
+
| Hook | Tool | Purpose |
|
|
923
|
+
| ------------ | ------------------------------------------------ | ---------------------------- |
|
|
924
|
+
| `pre-commit` | ESLint + Prettier | Code quality on staged files |
|
|
925
|
+
| `pre-push` | [Gitleaks](https://github.com/gitleaks/gitleaks) | Secret scanning before push |
|
|
926
|
+
|
|
927
|
+
Gitleaks must be [installed locally](https://github.com/gitleaks/gitleaks#installing). The pre-push hook will skip if Gitleaks is not available.
|
|
928
|
+
|
|
929
|
+
### Manual local checks
|
|
930
|
+
|
|
931
|
+
```bash
|
|
932
|
+
# Dependency audit (production only)
|
|
933
|
+
npm run audit:deps
|
|
934
|
+
|
|
935
|
+
# Secret scanning
|
|
936
|
+
npm run audit:secrets
|
|
937
|
+
|
|
938
|
+
# Full npm audit (all dependencies)
|
|
939
|
+
npm audit
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
---
|
|
943
|
+
|
|
722
944
|
## Contributing
|
|
723
945
|
|
|
724
946
|
Contributions are welcome. Please open an issue before submitting a pull request for significant changes.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { INestApplication } from '@nestjs/common';
|
|
2
|
+
export interface ApplyProblemDetailResponsesOptions {
|
|
3
|
+
statuses?: number[];
|
|
4
|
+
validationStatuses?: number[];
|
|
5
|
+
}
|
|
6
|
+
export declare function applyProblemDetailResponses(app: INestApplication, options?: ApplyProblemDetailResponsesOptions): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.applyProblemDetailResponses = applyProblemDetailResponses;
|
|
37
|
+
const core_1 = require("@nestjs/core");
|
|
38
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
39
|
+
const http = __importStar(require("http"));
|
|
40
|
+
const problem_detail_dto_1 = require("./problem-detail.dto");
|
|
41
|
+
function applyProblemDetailResponses(app, options) {
|
|
42
|
+
const discoveryService = app.get(core_1.DiscoveryService);
|
|
43
|
+
const controllers = discoveryService.getControllers();
|
|
44
|
+
const statuses = options?.statuses ?? [400, 500];
|
|
45
|
+
const validationStatuses = new Set(options?.validationStatuses ?? []);
|
|
46
|
+
for (const controller of controllers) {
|
|
47
|
+
if (!controller.metatype)
|
|
48
|
+
continue;
|
|
49
|
+
(0, swagger_1.ApiExtraModels)(problem_detail_dto_1.ProblemDetailDto, problem_detail_dto_1.ValidationProblemDetailDto)(controller.metatype);
|
|
50
|
+
for (const status of statuses) {
|
|
51
|
+
const dtoClass = validationStatuses.has(status)
|
|
52
|
+
? problem_detail_dto_1.ValidationProblemDetailDto
|
|
53
|
+
: problem_detail_dto_1.ProblemDetailDto;
|
|
54
|
+
(0, swagger_1.ApiResponse)({
|
|
55
|
+
status,
|
|
56
|
+
description: http.STATUS_CODES[status],
|
|
57
|
+
content: {
|
|
58
|
+
'application/problem+json': {
|
|
59
|
+
schema: { $ref: (0, swagger_1.getSchemaPath)(dtoClass) },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
})(controller.metatype);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=apply-problem-detail-responses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-problem-detail-responses.js","sourceRoot":"","sources":["../../src/swagger/apply-problem-detail-responses.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,kEA8BC;AAxED,uCAAgD;AAChD,6CAA6E;AAC7E,2CAA6B;AAC7B,6DAAoF;AAuCpF,SAAgB,2BAA2B,CACzC,GAAqB,EACrB,OAA4C;IAE5C,MAAM,gBAAgB,GAAG,GAAG,CAAC,GAAG,CAAC,uBAAgB,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,gBAAgB,CAAC,cAAc,EAAE,CAAC;IACtD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACjD,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,kBAAkB,IAAI,EAAE,CAAC,CAAC;IAEtE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,QAAQ;YAAE,SAAS;QAEnC,IAAA,wBAAc,EAAC,qCAAgB,EAAE,+CAA0B,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAElF,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC7C,CAAC,CAAC,+CAA0B;gBAC5B,CAAC,CAAC,qCAAgB,CAAC;YAErB,IAAA,qBAAW,EAAC;gBACV,MAAM;gBACN,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;gBACtC,OAAO,EAAE;oBACP,0BAA0B,EAAE;wBAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,IAAA,uBAAa,EAAC,QAAQ,CAAC,EAAE;qBAC1C;iBACF;aACF,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyProblemDetailResponses = exports.ValidationProblemDetailDto = exports.ValidationErrorDto = exports.ProblemDetailDto = void 0;
|
|
4
|
+
var problem_detail_dto_1 = require("./problem-detail.dto");
|
|
5
|
+
Object.defineProperty(exports, "ProblemDetailDto", { enumerable: true, get: function () { return problem_detail_dto_1.ProblemDetailDto; } });
|
|
6
|
+
Object.defineProperty(exports, "ValidationErrorDto", { enumerable: true, get: function () { return problem_detail_dto_1.ValidationErrorDto; } });
|
|
7
|
+
Object.defineProperty(exports, "ValidationProblemDetailDto", { enumerable: true, get: function () { return problem_detail_dto_1.ValidationProblemDetailDto; } });
|
|
8
|
+
var apply_problem_detail_responses_1 = require("./apply-problem-detail-responses");
|
|
9
|
+
Object.defineProperty(exports, "applyProblemDetailResponses", { enumerable: true, get: function () { return apply_problem_detail_responses_1.applyProblemDetailResponses; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/swagger/index.ts"],"names":[],"mappings":";;;AAAA,2DAI8B;AAH5B,sHAAA,gBAAgB,OAAA;AAChB,wHAAA,kBAAkB,OAAA;AAClB,gIAAA,0BAA0B,OAAA;AAE5B,mFAG0C;AAFxC,6IAAA,2BAA2B,OAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class ProblemDetailDto {
|
|
2
|
+
type?: string;
|
|
3
|
+
title?: string;
|
|
4
|
+
status: number;
|
|
5
|
+
detail?: string;
|
|
6
|
+
instance?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class ValidationErrorDto {
|
|
9
|
+
property: string;
|
|
10
|
+
constraints?: Record<string, string>;
|
|
11
|
+
children?: ValidationErrorDto[];
|
|
12
|
+
}
|
|
13
|
+
export declare class ValidationProblemDetailDto extends ProblemDetailDto {
|
|
14
|
+
errors: ValidationErrorDto[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ValidationProblemDetailDto = exports.ValidationErrorDto = exports.ProblemDetailDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
class ProblemDetailDto {
|
|
15
|
+
}
|
|
16
|
+
exports.ProblemDetailDto = ProblemDetailDto;
|
|
17
|
+
__decorate([
|
|
18
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
19
|
+
description: 'A URI reference that identifies the problem type.',
|
|
20
|
+
example: 'about:blank',
|
|
21
|
+
}),
|
|
22
|
+
__metadata("design:type", String)
|
|
23
|
+
], ProblemDetailDto.prototype, "type", void 0);
|
|
24
|
+
__decorate([
|
|
25
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
26
|
+
description: 'A short, human-readable summary of the problem type.',
|
|
27
|
+
example: 'Not Found',
|
|
28
|
+
}),
|
|
29
|
+
__metadata("design:type", String)
|
|
30
|
+
], ProblemDetailDto.prototype, "title", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, swagger_1.ApiProperty)({
|
|
33
|
+
description: 'The HTTP status code generated by the origin server.',
|
|
34
|
+
example: 404,
|
|
35
|
+
}),
|
|
36
|
+
__metadata("design:type", Number)
|
|
37
|
+
], ProblemDetailDto.prototype, "status", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
40
|
+
description: 'A human-readable explanation specific to this occurrence.',
|
|
41
|
+
example: 'The requested resource was not found.',
|
|
42
|
+
}),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], ProblemDetailDto.prototype, "detail", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
47
|
+
description: 'A URI reference that identifies the specific occurrence.',
|
|
48
|
+
}),
|
|
49
|
+
__metadata("design:type", String)
|
|
50
|
+
], ProblemDetailDto.prototype, "instance", void 0);
|
|
51
|
+
class ValidationErrorDto {
|
|
52
|
+
}
|
|
53
|
+
exports.ValidationErrorDto = ValidationErrorDto;
|
|
54
|
+
__decorate([
|
|
55
|
+
(0, swagger_1.ApiProperty)({
|
|
56
|
+
description: 'The property that failed validation.',
|
|
57
|
+
example: 'email',
|
|
58
|
+
}),
|
|
59
|
+
__metadata("design:type", String)
|
|
60
|
+
], ValidationErrorDto.prototype, "property", void 0);
|
|
61
|
+
__decorate([
|
|
62
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
63
|
+
description: 'Constraint name → error message map.',
|
|
64
|
+
example: { isEmail: 'email must be an email' },
|
|
65
|
+
type: 'object',
|
|
66
|
+
additionalProperties: { type: 'string' },
|
|
67
|
+
}),
|
|
68
|
+
__metadata("design:type", Object)
|
|
69
|
+
], ValidationErrorDto.prototype, "constraints", void 0);
|
|
70
|
+
__decorate([
|
|
71
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
72
|
+
description: 'Nested validation errors for child properties.',
|
|
73
|
+
type: () => [ValidationErrorDto],
|
|
74
|
+
}),
|
|
75
|
+
__metadata("design:type", Array)
|
|
76
|
+
], ValidationErrorDto.prototype, "children", void 0);
|
|
77
|
+
class ValidationProblemDetailDto extends ProblemDetailDto {
|
|
78
|
+
}
|
|
79
|
+
exports.ValidationProblemDetailDto = ValidationProblemDetailDto;
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, swagger_1.ApiProperty)({
|
|
82
|
+
description: 'Structured validation errors.',
|
|
83
|
+
type: [ValidationErrorDto],
|
|
84
|
+
}),
|
|
85
|
+
__metadata("design:type", Array)
|
|
86
|
+
], ValidationProblemDetailDto.prototype, "errors", void 0);
|
|
87
|
+
//# sourceMappingURL=problem-detail.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"problem-detail.dto.js","sourceRoot":"","sources":["../../src/swagger/problem-detail.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAAmE;AASnE,MAAa,gBAAgB;CA6B5B;AA7BD,4CA6BC;AAxBC;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,aAAa;KACvB,CAAC;;8CACY;AAMd;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,WAAW;KACrB,CAAC;;+CACa;AAMf;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,GAAG;KACb,CAAC;;gDACc;AAMhB;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,2DAA2D;QACxE,OAAO,EAAE,uCAAuC;KACjD,CAAC;;gDACc;AAKhB;IAHC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,0DAA0D;KACxE,CAAC;;kDACgB;AAOpB,MAAa,kBAAkB;CAoB9B;AApBD,gDAoBC;AAfC;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,OAAO;KACjB,CAAC;;oDACgB;AAQlB;IANC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE;QAC9C,IAAI,EAAE,QAAQ;QACd,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACzC,CAAC;;uDACmC;AAMrC;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,gDAAgD;QAC7D,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,kBAAkB,CAAC;KACjC,CAAC;;oDAC8B;AAclC,MAAa,0BAA2B,SAAQ,gBAAgB;CAM/D;AAND,gEAMC;AADC;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,+BAA+B;QAC5C,IAAI,EAAE,CAAC,kBAAkB,CAAC;KAC3B,CAAC;;0DAC4B"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camcima/nestjs-rfc9457",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "NestJS library for RFC 9457 Problem Details responses",
|
|
5
5
|
"author": "Carlos Cima",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./swagger": {
|
|
15
|
+
"types": "./dist/swagger/index.d.ts",
|
|
16
|
+
"default": "./dist/swagger/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
9
19
|
"files": [
|
|
10
20
|
"dist"
|
|
11
21
|
],
|
|
@@ -22,29 +32,37 @@
|
|
|
22
32
|
"test:e2e": "jest --testPathPattern=test/e2e",
|
|
23
33
|
"test:cov": "jest --coverage",
|
|
24
34
|
"prepublishOnly": "npm run build",
|
|
25
|
-
"release": "release-it"
|
|
35
|
+
"release": "release-it",
|
|
36
|
+
"audit:deps": "npm audit --omit=dev",
|
|
37
|
+
"audit:secrets": "gitleaks git --no-banner --redact -v"
|
|
26
38
|
},
|
|
27
39
|
"peerDependencies": {
|
|
28
40
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
29
41
|
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
30
42
|
"class-validator": "^0.14.0",
|
|
31
|
-
"reflect-metadata": "^0.1.13 || ^0.2.0"
|
|
43
|
+
"reflect-metadata": "^0.1.13 || ^0.2.0",
|
|
44
|
+
"@nestjs/swagger": "^7.0.0 || ^8.0.0 || ^11.0.0"
|
|
32
45
|
},
|
|
33
46
|
"peerDependenciesMeta": {
|
|
34
47
|
"class-validator": {
|
|
35
48
|
"optional": true
|
|
49
|
+
},
|
|
50
|
+
"@nestjs/swagger": {
|
|
51
|
+
"optional": true
|
|
36
52
|
}
|
|
37
53
|
},
|
|
38
54
|
"devDependencies": {
|
|
39
|
-
"@commitlint/cli": "^
|
|
40
|
-
"@commitlint/config-conventional": "^
|
|
41
|
-
"@nestjs/common": "^
|
|
42
|
-
"@nestjs/core": "^
|
|
43
|
-
"@nestjs/
|
|
44
|
-
"@nestjs/platform-
|
|
45
|
-
"@nestjs/
|
|
46
|
-
"@
|
|
47
|
-
"@types/
|
|
55
|
+
"@commitlint/cli": "^20.5.0",
|
|
56
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
57
|
+
"@nestjs/common": "^11.1.18",
|
|
58
|
+
"@nestjs/core": "^11.1.18",
|
|
59
|
+
"@nestjs/swagger": "^11.1.18",
|
|
60
|
+
"@nestjs/platform-express": "^11.1.18",
|
|
61
|
+
"@nestjs/platform-fastify": "^11.1.18",
|
|
62
|
+
"@nestjs/testing": "^11.1.18",
|
|
63
|
+
"@types/jest": "^30.0.0",
|
|
64
|
+
"@types/node": "^22.19.17",
|
|
65
|
+
"@types/supertest": "^7.2.0",
|
|
48
66
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
49
67
|
"@typescript-eslint/parser": "^7.0.0",
|
|
50
68
|
"class-transformer": "^0.5.0",
|
|
@@ -53,7 +71,7 @@
|
|
|
53
71
|
"eslint-config-prettier": "^9.0.0",
|
|
54
72
|
"eslint-plugin-prettier": "^5.0.0",
|
|
55
73
|
"fastify": "^4.0.0",
|
|
56
|
-
"jest": "^
|
|
74
|
+
"jest": "^30.3.0",
|
|
57
75
|
"lefthook": "^1.0.0",
|
|
58
76
|
"prettier": "^3.0.0",
|
|
59
77
|
"reflect-metadata": "^0.2.0",
|
|
@@ -62,7 +80,7 @@
|
|
|
62
80
|
"supertest": "^7.0.0",
|
|
63
81
|
"ts-jest": "^29.0.0",
|
|
64
82
|
"ts-node": "^10.9.2",
|
|
65
|
-
"typescript": "^
|
|
83
|
+
"typescript": "^6.0.2"
|
|
66
84
|
},
|
|
67
85
|
"repository": {
|
|
68
86
|
"type": "git",
|