@fluojs/openapi 1.0.3 → 2.0.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.ko.md +80 -11
- package/README.md +80 -11
- package/dist/decorators.d.ts +7 -5
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +9 -7
- package/dist/openapi-module.d.ts +26 -8
- package/dist/openapi-module.d.ts.map +1 -1
- package/dist/openapi-module.js +39 -44
- package/dist/path-item.d.ts +62 -0
- package/dist/path-item.d.ts.map +1 -0
- package/dist/path-item.js +53 -0
- package/dist/schema-bounds.d.ts +9 -0
- package/dist/schema-bounds.d.ts.map +1 -0
- package/dist/schema-bounds.js +175 -0
- package/dist/schema-builder.d.ts +3 -6
- package/dist/schema-builder.d.ts.map +1 -1
- package/dist/schema-builder.js +27 -14
- package/dist/swagger-ui.d.ts +29 -0
- package/dist/swagger-ui.d.ts.map +1 -0
- package/dist/swagger-ui.js +67 -0
- package/package.json +8 -7
package/README.ko.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p><a href="./README.md"><kbd>English</kbd></a> <strong><kbd>한국어</kbd></strong></p>
|
|
4
4
|
|
|
5
|
-
fluo를 위한
|
|
5
|
+
fluo를 위한 descriptor-driven OpenAPI 3.1.0 문서 생성 패키지입니다. 명시적 문서 metadata를 위한 standard decorator와 선택적 Swagger UI를 지원합니다.
|
|
6
6
|
|
|
7
7
|
## 목차
|
|
8
8
|
|
|
@@ -20,12 +20,15 @@ fluo를 위한 데코레이터 기반 OpenAPI 3.1.0 문서 생성 패키지입
|
|
|
20
20
|
pnpm add @fluojs/openapi
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
`@fluojs/openapi`는 Node.js `>=24.0.0 <27`을 지원하며 `engines.node`로 정확히 이 범위를 선언합니다. 이 package-owned 지원 계약은 Node 24 미만과 Node 27 이상을 제외하며 portable `@fluojs/runtime`에는 package-wide Node engine이 없습니다. 이전 1.x 릴리스는 `engines.node >=20.0.0`을 광고했습니다.
|
|
24
|
+
|
|
23
25
|
## 사용 시점
|
|
24
26
|
|
|
25
27
|
- **Swagger UI**를 사용하여 REST API에 대한 대화형 문서를 제공하고 싶을 때.
|
|
26
28
|
- 클라이언트 생성 또는 테스트를 위해 기계 읽기 가능한 **OpenAPI 3.1.0** 명세가 필요할 때.
|
|
27
29
|
- 표준 데코레이터를 사용하여 API 문서와 코드를 동기화된 상태로 유지하고 싶을 때.
|
|
28
|
-
- DTO
|
|
30
|
+
- DTO binding/validation metadata에서 request model을 파생하고 response model을 명시적으로 선언해야 할 때.
|
|
31
|
+
- 하나의 application에서 여러 API version 또는 audience를 위해 JSON/UI route를 분리해야 할 때.
|
|
29
32
|
|
|
30
33
|
## 빠른 시작
|
|
31
34
|
|
|
@@ -34,7 +37,7 @@ pnpm add @fluojs/openapi
|
|
|
34
37
|
```typescript
|
|
35
38
|
import { Controller, Get } from '@fluojs/http';
|
|
36
39
|
import { Module } from '@fluojs/core';
|
|
37
|
-
import { bootstrapNodeApplication } from '@fluojs/
|
|
40
|
+
import { bootstrapNodeApplication } from '@fluojs/platform-nodejs';
|
|
38
41
|
import { OpenApiModule, ApiOperation, ApiResponse, ApiTag } from '@fluojs/openapi';
|
|
39
42
|
|
|
40
43
|
@ApiTag('Users')
|
|
@@ -73,8 +76,27 @@ await app.listen(3000);
|
|
|
73
76
|
|
|
74
77
|
## 핵심 기능
|
|
75
78
|
|
|
79
|
+
### 빈 decorator options
|
|
80
|
+
|
|
81
|
+
`@ApiOperation()` / `@ApiOperation(undefined)`와 `@ApiBody()` / `@ApiBody(undefined)`는
|
|
82
|
+
기존 `{}` 의미를 사용합니다. Summary, description, deprecated, required, schema를 임의로
|
|
83
|
+
생성하지 않습니다. 빈 body metadata는 DTO에서 추론한 body를 유지하고, 추론한 body가 없으면
|
|
84
|
+
`requestBody`를 추가하지 않습니다. 빈 write도 stacking의 이전 metadata를 덮어쓸 수 있으므로
|
|
85
|
+
decorator 자체 생략과 항상 같지는 않습니다. 기존 적용 시 `null` 실패를 유지합니다.
|
|
86
|
+
`ApiTag(tag)`, `ApiResponse(status, options?)`, parameter/security name은 계속 필수이며
|
|
87
|
+
지원하는 OpenAPI Path Item method 집합은 바뀌지 않습니다.
|
|
88
|
+
|
|
76
89
|
### 자동 명세 생성
|
|
77
|
-
fluo는
|
|
90
|
+
fluo는 `sources`와 `descriptors`로 전달된 controller 및 handler descriptor만 조사하여 OpenAPI 3.1.0 문서를 작성합니다. 이 명시적 입력 집합의 경로, 메서드, 파라미터, 요청 바디가 포함되며, controller를 application module에 import하는 것만으로는 자동 추가되지 않습니다.
|
|
91
|
+
|
|
92
|
+
### OpenAPI 3.1 Path Item 검증
|
|
93
|
+
Builder는 표준 Path Item operation인 `get`, `put`, `post`, `delete`, `options`, `head`, `patch`, `trace`만 생성합니다. Fluo catch-all `ALL` descriptor는 runtime routing 입력이지 OpenAPI operation이 아니므로, 비표준 `all` key로 직렬화하지 않고 문서 생성을 거부합니다. 지원하지 않는 다른 descriptor method도 같은 path-specific error로 실패합니다.
|
|
94
|
+
|
|
95
|
+
`documentTransform` 이후에는 모든 Path Item을 다시 검증합니다. Transform은 OpenAPI 3.1 operation(`trace` 포함), fixed field(`$ref`, `summary`, `description`, `servers`, `parameters`), `x-*` specification extension을 사용할 수 있습니다. `all`, `query` 또는 기타 알 수 없는 key는 문서가 노출되기 전에 생성을 실패시킵니다.
|
|
96
|
+
|
|
97
|
+
### 2.0으로 마이그레이션
|
|
98
|
+
|
|
99
|
+
업그레이드하기 전에 모든 `@All()` route 또는 custom handler descriptor를 각각 지원되는 HTTP method route로 바꾸거나 OpenAPI 입력에서 제외하세요. `documentTransform`에서는 `all`, `query` 같은 비표준 Path Item key를 제거하고 표준 operation, fixed field, `x-*` extension만 유지하세요. 지원하지 않는 입력은 이제 잘못된 문서를 생성하는 대신 문서 생성 단계에서 예외를 발생시킵니다.
|
|
78
100
|
|
|
79
101
|
### 응답 미디어 타입
|
|
80
102
|
HTTP 핸들러가 `@fluojs/http`의 `@Produces(...)`를 선언하면, 생성된 OpenAPI 응답은 해당 미디어 타입을 response `content` 키로 사용합니다. 예를 들어 `@ApiResponse(...)` 스키마가 있는 핸들러에 `@Produces('application/json', 'application/problem+json')`를 붙이면, `application/json`만으로 되돌아가지 않고 두 미디어 타입 모두 같은 응답 스키마로 방출합니다.
|
|
@@ -82,25 +104,70 @@ HTTP 핸들러가 `@fluojs/http`의 `@Produces(...)`를 선언하면, 생성된
|
|
|
82
104
|
### 기본 성공 응답
|
|
83
105
|
핸들러가 `@ApiResponse(...)` 또는 `@HttpCode(...)`를 선언하지 않으면 OpenAPI builder는 메서드만 기준으로 한 암묵적 기본값을 적용합니다. `POST` 핸들러는 기본적으로 `201`, 그 밖의 메서드는 `200`을 사용합니다. `DELETE`와 `OPTIONS`처럼 본문이 없거나 런타임 결과에 따라 달라질 수 있는 경우에는 `@HttpCode(...)` 또는 `@ApiResponse(...)`로 의도한 성공 상태를 명시하세요.
|
|
84
106
|
|
|
107
|
+
### 응답 문서화 경계
|
|
108
|
+
Builder는 handler 반환값이나 TypeScript 반환 타입을 검사해 response content를 추론하지 않습니다. 기본 success response에는 status와 `OK` description만 포함됩니다. OpenAPI 문서에 response body를 설명해야 하면 `@ApiResponse(...)`에 `schema` 또는 `type`을 추가하세요. 둘 중 어느 것도 없으면 명시적 response도 status와 description만 포함합니다.
|
|
109
|
+
|
|
85
110
|
### 통합 DTO 스키마
|
|
86
|
-
`@fluojs/validation`과
|
|
111
|
+
`@fluojs/validation`과 함께 DTO binding 및 validation metadata에서 request schema를 파생합니다. Response DTO는 `@ApiResponse(..., { type: ResponseDto })` 또는 `extraModels`처럼 명시적으로 참조할 때만 OpenAPI component가 됩니다.
|
|
112
|
+
|
|
113
|
+
### OpenAPI 3.1 배타적 경계
|
|
114
|
+
`OpenApiSchemaObject`는 OpenAPI 3.1의 숫자 `exclusiveMinimum` 및 `exclusiveMaximum` 값을 받으면서 기존 boolean metadata와의 호환성도 유지합니다. `minimum` 또는 `maximum`과 함께 사용한 `true` 플래그는 생성 문서에서 대응하는 숫자 배타적 경계로 변환되고, `false` 플래그는 생략되는 대신 포괄 경계는 유지됩니다. 유한한 숫자 배타적 경계는 변경 없이 통과합니다. 유한한 대응 경계가 없는 `true` 플래그나 유한하지 않은 숫자 배타적 경계는 잘못된 OpenAPI 3.1 schema를 생성하는 대신 문서 생성을 실패시킵니다. 같은 정규화는 문서가 노출되기 전에 `documentTransform` 이후에도 실행됩니다.
|
|
115
|
+
|
|
116
|
+
### OpenAPI 3.1 Nullable 스키마
|
|
117
|
+
`OpenApiSchemaObject`는 호환성 입력으로 legacy boolean `nullable` keyword를 계속 받지만 생성되는 OpenAPI 3.1 문서에는 이를 내보내지 않습니다. `nullable: true`는 scalar 및 array constraint를 보존하면서 선언된 `type` union에 `null`을 추가합니다. `$ref` schema를 포함해 `type`이 없는 schema는 `{ type: 'null' }`과의 `anyOf` union으로 변환됩니다. `nullable: false`는 schema를 바꾸지 않고 제거됩니다. 기존 null union에는 `null`을 중복 추가하지 않으며, 이 재귀 정규화는 `documentTransform` 뒤에도 실행됩니다.
|
|
87
118
|
|
|
88
119
|
### 버전 관리 지원
|
|
89
120
|
`@fluojs/http`의 URI 기반 버전 관리를 자동으로 처리합니다. OpenAPI 경로에 해결된 버전 경로가 올바르게 반영됩니다.
|
|
90
121
|
|
|
91
122
|
### 보안 문서화
|
|
92
|
-
`@ApiBearerAuth()` 및 `@ApiSecurity()`를 사용하여 Bearer 토큰이나 API 키와 같은 보안 요구사항을 쉽게 문서화할 수 있습니다.
|
|
123
|
+
`@ApiBearerAuth()` 및 `@ApiSecurity(name, scopes?)`를 사용하여 Bearer 토큰이나 API 키와 같은 보안 요구사항을 쉽게 문서화할 수 있습니다.
|
|
93
124
|
|
|
94
|
-
같은 scheme에 대해 여러 `@ApiSecurity()` 데코레이터를 쌓으면, 해당 scheme의 scope가 하나의 누적 OpenAPI security requirement로 병합됩니다. 따라서 라우트가 `['reports:read']`와 `['reports:write', 'reports:read']`처럼 겹치는 scope를 선언해도 OAuth 스타일 요구사항은 결정적으로 유지되며, 서로 다른 scheme은 별도 requirement로 남습니다.
|
|
125
|
+
같은 scheme에 대해 여러 `@ApiSecurity(name, scopes?)` 데코레이터를 쌓으면, 해당 scheme의 scope가 하나의 누적 OpenAPI security requirement로 병합됩니다. 따라서 라우트가 `['reports:read']`와 `['reports:write', 'reports:read']`처럼 겹치는 scope를 선언해도 OAuth 스타일 요구사항은 결정적으로 유지되며, 서로 다른 scheme은 별도 requirement로 남습니다.
|
|
95
126
|
|
|
96
127
|
### 결정적인 Swagger UI 자산
|
|
97
128
|
`ui: true`를 활성화하면 생성되는 `/docs` 페이지는 정확한 `swagger-ui-dist` 버전의 자산을 참조하여 패키지 릴리스마다 동일한 동작을 유지합니다. 오프라인 또는 CSP 제어 환경에서 자체 호스팅 자산이 필요하면 `swaggerUiAssets.cssUrl`과 `swaggerUiAssets.jsBundleUrl`을 설정하세요. 생성된 HTML은 해당 URL을 이스케이프하며 Swagger UI 인스턴스를 `window.ui`에 노출하지 않습니다.
|
|
98
129
|
|
|
130
|
+
### 설정 가능한 문서 라우트
|
|
131
|
+
각 `OpenApiModule` 등록은 `documentPath`에서 JSON을 제공하고 `uiPath`에 Swagger UI route를 예약합니다. 기본값은 계속 `/openapi.json`과 `/docs`이므로 기존 application은 설정을 바꿀 필요가 없습니다. 하나의 application에서 여러 OpenAPI module을 import할 때는 두 path를 모두 지정하세요.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
@Module({
|
|
135
|
+
imports: [
|
|
136
|
+
OpenApiModule.forRoot({
|
|
137
|
+
documentPath: '/openapi/public.json',
|
|
138
|
+
sources: [{ controllerToken: PublicController }],
|
|
139
|
+
title: 'Public API',
|
|
140
|
+
ui: true,
|
|
141
|
+
uiPath: '/docs/public',
|
|
142
|
+
version: '1.0.0',
|
|
143
|
+
}),
|
|
144
|
+
OpenApiModule.forRoot({
|
|
145
|
+
documentPath: '/openapi/admin.json',
|
|
146
|
+
sources: [{ controllerToken: AdminController }],
|
|
147
|
+
title: 'Admin API',
|
|
148
|
+
ui: true,
|
|
149
|
+
uiPath: '/docs/admin',
|
|
150
|
+
version: '1.0.0',
|
|
151
|
+
}),
|
|
152
|
+
],
|
|
153
|
+
})
|
|
154
|
+
class AppModule {}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Path는 `@fluojs/http` route grammar를 따르며 중복 slash와 trailing slash를 정규화합니다. Route collision에는 document descriptor precedence가 적용되지 않습니다. JSON/UI path끼리, 서로 다른 OpenAPI module끼리, 또는 다른 application controller와 정규화된 `GET` route가 겹치면 application bootstrap이 `RouteConflictError`로 실패합니다. `ui`가 false여도 UI route는 예약되므로, 설정한 endpoint는 문서화된 `Swagger UI is disabled.` not-found response를 반환할 수 있습니다.
|
|
158
|
+
|
|
99
159
|
### 모듈 옵션 결정성
|
|
100
|
-
`OpenApiModule.forRoot(...)`는 등록 시점에 옵션을 스냅샷하고 freeze합니다. 등록 후 원본 options 객체, `sources`, `descriptors`, `securitySchemes`, `extraModels`, `swaggerUiAssets`를 변경해도 제공되는 OpenAPI 문서나
|
|
160
|
+
`OpenApiModule.forRoot(...)`는 등록 시점에 옵션을 스냅샷하고 freeze합니다. 등록 후 원본 options 객체, `documentPath`, `uiPath`, `sources`, `descriptors`, `securitySchemes`, `extraModels`, `swaggerUiAssets`를 변경해도 제공되는 OpenAPI 문서나 UI HTML은 바뀌지 않습니다. 생성된 singleton 문서도 defensive copy로 제공되므로 downstream response serialization이나 테스트가 이후 요청에 쓰이는 저장 문서를 변경할 수 없습니다. `OpenApiModule.forRootAsync(...)`는 module compile 전에 outer registration의 `documentPath`와 `uiPath`를 고정하고, async document-options factory가 resolve된 뒤 같은 스냅샷을 적용하며, factory 실패는 bootstrap 중 전파됩니다.
|
|
101
161
|
|
|
102
162
|
### Async 등록과 옵션
|
|
103
|
-
title/version/source 설정이 DI나 async setup에서 나오는 경우 `OpenApiModule.forRootAsync(...)`를 사용합니다.
|
|
163
|
+
title/version/source 설정이 DI나 async setup에서 나오는 경우 `OpenApiModule.forRootAsync(...)`를 사용합니다. 등록 시점의 `documentPath`와 `uiPath`는 `inject`, `useFactory` 옆에 두고, factory에서는 `sources`, `descriptors`, `securitySchemes`, `extraModels`, `defaultErrorResponsesPolicy`, `documentTransform`, `ui`, `swaggerUiAssets`를 반환합니다. `defaultErrorResponsesPolicy`는 기본적으로 표준 error response와 `ErrorResponse` schema를 주입하며, `documentTransform`은 문서 생성 뒤 제공되기 전에 실행됩니다.
|
|
164
|
+
|
|
165
|
+
### NestJS 마이그레이션 계약 차이
|
|
166
|
+
생성 문서는 NestJS Swagger와 일대일 호환 계층이 아닙니다. fluo는 기본적으로 명시적으로 선언한 응답을 대체하지 않으면서 `400`, `401`, `403`, `404`, `500` 응답과 공용 `ErrorResponse` schema를 추가합니다. 클라이언트를 다시 생성하기 전에 생성된 error contract를 검증하고, legacy 문서에 이 기본 응답이 들어가면 안 되는 경우 `defaultErrorResponsesPolicy: 'omit'`을 설정하세요.
|
|
167
|
+
|
|
168
|
+
fluo는 controller tag, handler name, HTTP method, normalized path에서 각 `operationId`를 결정론적으로 만듭니다. 충돌에는 숫자 suffix가 붙습니다. 생성된 client가 legacy identifier에 의존한다면 문서를 제공하기 전에 `documentTransform`에서 생성된 operation ID를 변경하고, 변환된 문서를 client generator로 검증하세요.
|
|
169
|
+
|
|
170
|
+
`forRootAsync(...)`에서는 `documentPath`와 `uiPath`의 route가 `useFactory(...)`가 resolve되기 전에 compile되므로 두 값은 바깥 registration option입니다. 이 path들은 `inject`와 `useFactory` 옆에 두고 factory에서는 document configuration만 반환하세요. factory가 반환한 path로는 이미 등록된 route를 다시 구성할 수 없습니다.
|
|
104
171
|
|
|
105
172
|
## 공개 API
|
|
106
173
|
|
|
@@ -109,12 +176,13 @@ title/version/source 설정이 DI나 async setup에서 나오는 경우 `OpenApi
|
|
|
109
176
|
- `ApiBody`, `ApiParam`, `ApiQuery`, `ApiHeader`, `ApiCookie`: 이름이 겹칠 때 추론된 요청 문서를 대체하는 명시적 요청 본문 및 파라미터 문서화 데코레이터.
|
|
110
177
|
- `ApiBearerAuth`, `ApiSecurity`: 보안 요구사항 데코레이터.
|
|
111
178
|
- `ApiExcludeEndpoint`: 특정 핸들러를 문서화에서 제외.
|
|
179
|
+
- `ApiOperationOptions`, `ApiResponseOptions`, `ApiParameterOptions`, `ApiBodyOptions`: `@ApiOperation(...)`, `@ApiResponse(...)`, `@ApiParam(...)`, `@ApiQuery(...)`, `@ApiHeader(...)`, `@ApiCookie(...)`, `@ApiBody(...)`가 받는 데코레이터 옵션 타입.
|
|
112
180
|
- `buildOpenApiDocument`: 프로그래밍 방식의 문서 빌더 (저수준).
|
|
113
181
|
- `OpenApiHandlerRegistry`: 고급 통합에서 문서 생성 전에 handler descriptor를 스냅샷하는 mutable descriptor registry.
|
|
114
182
|
- `getControllerTags`, `getMethodApiMetadata`: 고급 테스트와 통합 tooling을 위한 metadata reader.
|
|
115
|
-
- `OpenApiModuleOptions`, `OpenApiSwaggerUiAssetsOptions`, `BuildOpenApiDocumentOptions`, `DefaultErrorResponsesPolicy`: module과 builder integration을 위한 option type.
|
|
183
|
+
- `OpenApiModuleOptions`, `OpenApiAsyncModuleOptions`, `OpenApiRouteOptions`, `OpenApiSwaggerUiAssetsOptions`, `BuildOpenApiDocumentOptions`, `DefaultErrorResponsesPolicy`: module과 builder integration을 위한 option type.
|
|
116
184
|
- `OpenApiDocument`, `OpenApiSecuritySchemeObject` 및 관련 OpenAPI shape type: 테스트, tooling, integration을 위한 typed document surface.
|
|
117
|
-
- `OpenApiSchemaObject`: 명시적 `@ApiBody(...)` 및 `@ApiResponse(...)` 스키마를 위한 타입화된 스키마 표면입니다. OpenAPI 3.1 조합(`allOf`, `oneOf`, `anyOf`), 객체/배열 제약, examples/defaults, 읽기/쓰기/Deprecated 주석을 포함합니다.
|
|
185
|
+
- `OpenApiSchemaObject`: 명시적 `@ApiBody(...)` 및 `@ApiResponse(...)` 스키마를 위한 타입화된 스키마 표면입니다. OpenAPI 3.1 조합(`allOf`, `oneOf`, `anyOf`), legacy `nullable` 입력과 호환되는 null union, 객체/배열 제약, examples/defaults, 읽기/쓰기/Deprecated 주석을 포함합니다.
|
|
118
186
|
|
|
119
187
|
## 관련 패키지
|
|
120
188
|
|
|
@@ -125,4 +193,5 @@ title/version/source 설정이 DI나 async setup에서 나오는 경우 `OpenApi
|
|
|
125
193
|
## 예제 소스
|
|
126
194
|
|
|
127
195
|
- `packages/openapi/src/openapi-module.test.ts`: 통합 테스트 및 사용 예제.
|
|
196
|
+
- `packages/openapi/src/openapi-module-routes.test.ts`: 기본/custom/multi-document/route-collision 예제.
|
|
128
197
|
- `packages/openapi/src/schema-builder.test.ts`: 문서 builder와 schema generation 예제.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p><strong><kbd>English</kbd></strong> <a href="./README.ko.md"><kbd>한국어</kbd></a></p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Descriptor-driven OpenAPI 3.1.0 document generation for fluo, with standard decorators for explicit documentation metadata and optional Swagger UI support.
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
8
|
|
|
@@ -20,12 +20,15 @@ Decorator-based OpenAPI 3.1.0 document generation for fluo. Automatically genera
|
|
|
20
20
|
pnpm add @fluojs/openapi
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
`@fluojs/openapi` supports Node.js `>=24.0.0 <27` and declares that exact range through `engines.node`. That package-owned support contract excludes Node versions below 24 and Node 27+; portable `@fluojs/runtime` has no package-wide Node engine. Earlier 1.x releases advertised `engines.node >=20.0.0`.
|
|
24
|
+
|
|
23
25
|
## When to Use
|
|
24
26
|
|
|
25
27
|
- When you want to provide interactive documentation for your REST API using **Swagger UI**.
|
|
26
28
|
- When you need a machine-readable **OpenAPI 3.1.0** specification for client generation or testing.
|
|
27
29
|
- When you want to keep your API documentation in sync with your code using standard decorators.
|
|
28
|
-
- When you need to
|
|
30
|
+
- When you need to derive request models from DTO binding/validation metadata and declare response models explicitly.
|
|
31
|
+
- When one application needs separate JSON and UI routes for multiple API versions or audiences.
|
|
29
32
|
|
|
30
33
|
## Quick Start
|
|
31
34
|
|
|
@@ -34,7 +37,7 @@ Register the `OpenApiModule` and pass `sources`, prebuilt `descriptors`, or both
|
|
|
34
37
|
```typescript
|
|
35
38
|
import { Controller, Get } from '@fluojs/http';
|
|
36
39
|
import { Module } from '@fluojs/core';
|
|
37
|
-
import { bootstrapNodeApplication } from '@fluojs/
|
|
40
|
+
import { bootstrapNodeApplication } from '@fluojs/platform-nodejs';
|
|
38
41
|
import { OpenApiModule, ApiOperation, ApiResponse, ApiTag } from '@fluojs/openapi';
|
|
39
42
|
|
|
40
43
|
@ApiTag('Users')
|
|
@@ -73,8 +76,27 @@ When a prebuilt descriptor and a discovered source resolve to the same OpenAPI p
|
|
|
73
76
|
|
|
74
77
|
## Core Capabilities
|
|
75
78
|
|
|
79
|
+
### Empty decorator options
|
|
80
|
+
|
|
81
|
+
`@ApiOperation()` / `@ApiOperation(undefined)` and `@ApiBody()` / `@ApiBody(undefined)`
|
|
82
|
+
use the existing `{}` semantics. No summary, description, deprecated flag, required flag,
|
|
83
|
+
or schema is invented. Empty body metadata preserves a DTO-inferred body and adds no
|
|
84
|
+
`requestBody` when none is inferred. Empty writes can overwrite earlier stacked metadata,
|
|
85
|
+
so these calls are not always equivalent to omitting the decorator. Existing application-time
|
|
86
|
+
`null` failures remain. `ApiTag(tag)`, `ApiResponse(status, options?)`, and parameter/security
|
|
87
|
+
names remain required; the supported OpenAPI Path Item methods do not change.
|
|
88
|
+
|
|
76
89
|
### Automated Specification Generation
|
|
77
|
-
fluo inspects
|
|
90
|
+
fluo inspects only the controllers and handler descriptors supplied through `sources` and `descriptors` to build an OpenAPI 3.1.0 document. This includes paths, methods, parameters, and request bodies for that explicit input set; importing a controller into an application module does not add it automatically.
|
|
91
|
+
|
|
92
|
+
### OpenAPI 3.1 Path Item Validation
|
|
93
|
+
The builder emits only standard Path Item operations: `get`, `put`, `post`, `delete`, `options`, `head`, `patch`, and `trace`. Fluo catch-all `ALL` descriptors are runtime routing inputs, not OpenAPI operations, so document generation rejects them instead of serializing a nonstandard `all` key. Unsupported descriptor methods fail with the same path-specific error.
|
|
94
|
+
|
|
95
|
+
After `documentTransform`, every Path Item is validated again. Transforms may use the OpenAPI 3.1 operations (including `trace`), fixed fields (`$ref`, `summary`, `description`, `servers`, and `parameters`), and `x-*` specification extensions. Keys such as `all`, `query`, or other unknown fields fail document generation before the document is exposed.
|
|
96
|
+
|
|
97
|
+
### Migrating to 2.0
|
|
98
|
+
|
|
99
|
+
Before upgrading, replace every `@All()` route or custom handler descriptor with separate supported HTTP method routes, or exclude it from OpenAPI input. In `documentTransform`, remove nonstandard Path Item keys such as `all` and `query`; retain only standard operations, fixed fields, and `x-*` extensions. Unsupported input now throws during document generation instead of emitting an invalid document.
|
|
78
100
|
|
|
79
101
|
### Response Media Types
|
|
80
102
|
When an HTTP handler declares `@Produces(...)` from `@fluojs/http`, generated OpenAPI responses use those media types as the response `content` keys. For example, `@Produces('application/json', 'application/problem+json')` on a handler with an `@ApiResponse(...)` schema emits both media types with the same response schema instead of silently falling back to only `application/json`.
|
|
@@ -82,25 +104,70 @@ When an HTTP handler declares `@Produces(...)` from `@fluojs/http`, generated Op
|
|
|
82
104
|
### Default Success Responses
|
|
83
105
|
When a handler does not declare `@ApiResponse(...)` or `@HttpCode(...)`, the OpenAPI builder applies method-only implicit defaults: `POST` handlers default to `201`, and other methods default to `200`. Bodyless or runtime-dependent cases such as `DELETE` and `OPTIONS` should declare the intended success status explicitly with `@HttpCode(...)` or `@ApiResponse(...)`.
|
|
84
106
|
|
|
107
|
+
### Response Documentation Boundary
|
|
108
|
+
The builder does not inspect handler return values or TypeScript return types to infer response content. A default success response contains only its status and the description `OK`. Add `@ApiResponse(...)` with `schema` or `type` when the OpenAPI document must describe a response body; without either field, an explicit response still contains status and description only.
|
|
109
|
+
|
|
85
110
|
### Integrated DTO Schemas
|
|
86
|
-
Works
|
|
111
|
+
Works with `@fluojs/validation` to derive request schemas from DTO binding and validation metadata. Response DTOs become OpenAPI components only when they are referenced explicitly, such as with `@ApiResponse(..., { type: ResponseDto })` or `extraModels`.
|
|
112
|
+
|
|
113
|
+
### OpenAPI 3.1 Exclusive Bounds
|
|
114
|
+
`OpenApiSchemaObject` accepts OpenAPI 3.1 numeric `exclusiveMinimum` and `exclusiveMaximum` values while retaining compatibility with legacy boolean metadata. A `true` flag paired with `minimum` or `maximum` becomes the corresponding numeric exclusive bound in the emitted document, and a `false` flag is omitted while its inclusive bound remains. Finite numeric exclusive bounds pass through unchanged. A `true` flag without a finite paired bound, or a non-finite numeric exclusive bound, fails document generation instead of emitting an invalid OpenAPI 3.1 schema. The same normalization runs after `documentTransform` before the document is exposed.
|
|
115
|
+
|
|
116
|
+
### OpenAPI 3.1 Nullable Schemas
|
|
117
|
+
`OpenApiSchemaObject` continues to accept the legacy boolean `nullable` keyword as compatibility input, but generated OpenAPI 3.1 documents never emit it. `nullable: true` adds `null` to a declared `type` union while preserving scalar and array constraints; schemas without `type`, including `$ref` schemas, become an `anyOf` union with `{ type: 'null' }`. `nullable: false` is removed without changing the schema. Existing null unions are not duplicated, and the recursive normalization also runs after `documentTransform`.
|
|
87
118
|
|
|
88
119
|
### Versioning Support
|
|
89
120
|
Handles URI-based versioning from `@fluojs/http` automatically. Your OpenAPI paths will correctly reflect the resolved versioned routes.
|
|
90
121
|
|
|
91
122
|
### Security Documentation
|
|
92
|
-
Easily document authentication requirements like Bearer tokens or API keys using `@ApiBearerAuth()` and `@ApiSecurity()`.
|
|
123
|
+
Easily document authentication requirements like Bearer tokens or API keys using `@ApiBearerAuth()` and `@ApiSecurity(name, scopes?)`.
|
|
93
124
|
|
|
94
|
-
Stacking multiple `@ApiSecurity()` decorators for the same scheme merges scopes into one cumulative OpenAPI security requirement for that scheme. This keeps OAuth-style requirements deterministic when a route declares overlapping scopes such as `['reports:read']` and `['reports:write', 'reports:read']`, while different schemes remain separate requirements.
|
|
125
|
+
Stacking multiple `@ApiSecurity(name, scopes?)` decorators for the same scheme merges scopes into one cumulative OpenAPI security requirement for that scheme. This keeps OAuth-style requirements deterministic when a route declares overlapping scopes such as `['reports:read']` and `['reports:write', 'reports:read']`, while different schemes remain separate requirements.
|
|
95
126
|
|
|
96
127
|
### Deterministic Swagger UI Assets
|
|
97
128
|
When `ui: true` is enabled, the generated `/docs` page references an exact `swagger-ui-dist` asset version so release behavior stays deterministic across package updates. If your deployment requires self-hosted assets for offline or CSP-controlled environments, set `swaggerUiAssets.cssUrl` and `swaggerUiAssets.jsBundleUrl`; the generated HTML escapes those URLs and does not expose the Swagger UI instance on `window.ui`.
|
|
98
129
|
|
|
130
|
+
### Configurable Document Routes
|
|
131
|
+
Each `OpenApiModule` registration serves JSON at `documentPath` and reserves its Swagger UI route at `uiPath`. The defaults remain `/openapi.json` and `/docs`, so existing applications do not need configuration changes. Set both paths when one application imports multiple OpenAPI modules:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
@Module({
|
|
135
|
+
imports: [
|
|
136
|
+
OpenApiModule.forRoot({
|
|
137
|
+
documentPath: '/openapi/public.json',
|
|
138
|
+
sources: [{ controllerToken: PublicController }],
|
|
139
|
+
title: 'Public API',
|
|
140
|
+
ui: true,
|
|
141
|
+
uiPath: '/docs/public',
|
|
142
|
+
version: '1.0.0',
|
|
143
|
+
}),
|
|
144
|
+
OpenApiModule.forRoot({
|
|
145
|
+
documentPath: '/openapi/admin.json',
|
|
146
|
+
sources: [{ controllerToken: AdminController }],
|
|
147
|
+
title: 'Admin API',
|
|
148
|
+
ui: true,
|
|
149
|
+
uiPath: '/docs/admin',
|
|
150
|
+
version: '1.0.0',
|
|
151
|
+
}),
|
|
152
|
+
],
|
|
153
|
+
})
|
|
154
|
+
class AppModule {}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Paths follow the `@fluojs/http` route grammar and normalize duplicate or trailing slashes. Route collisions do not use document-descriptor precedence: if two normalized `GET` routes collide—between JSON and UI paths, separate OpenAPI modules, or another application controller—application bootstrap fails with `RouteConflictError`. The UI route remains reserved when `ui` is false so the configured endpoint can return the documented `Swagger UI is disabled.` not-found response.
|
|
158
|
+
|
|
99
159
|
### Module Option Determinism
|
|
100
|
-
`OpenApiModule.forRoot(...)` snapshots and freezes its options at registration time. Mutating the original options object, `sources`, `descriptors`, `securitySchemes`, `extraModels`, or `swaggerUiAssets` after registration does not alter the served OpenAPI document or
|
|
160
|
+
`OpenApiModule.forRoot(...)` snapshots and freezes its options at registration time. Mutating the original options object, `documentPath`, `uiPath`, `sources`, `descriptors`, `securitySchemes`, `extraModels`, or `swaggerUiAssets` after registration does not alter the served OpenAPI document or UI HTML. The generated singleton document is also served through defensive copies, so downstream response serialization or tests cannot mutate the stored document for later requests. `OpenApiModule.forRootAsync(...)` fixes `documentPath` and `uiPath` from the outer registration before module compilation, applies the same snapshot once the async document-options factory resolves, and propagates factory failures during bootstrap.
|
|
101
161
|
|
|
102
162
|
### Async Registration and Options
|
|
103
|
-
Use `OpenApiModule.forRootAsync(...)` when title/version/source configuration comes from DI or async setup.
|
|
163
|
+
Use `OpenApiModule.forRootAsync(...)` when title/version/source configuration comes from DI or async setup. Put registration-time `documentPath` and `uiPath` beside `inject` and `useFactory`; return `sources`, `descriptors`, `securitySchemes`, `extraModels`, `defaultErrorResponsesPolicy`, `documentTransform`, `ui`, and `swaggerUiAssets` from the factory. `defaultErrorResponsesPolicy` defaults to injecting standard error responses and an `ErrorResponse` schema, while `documentTransform` runs after document generation and before serving.
|
|
164
|
+
|
|
165
|
+
### NestJS Migration Contract Differences
|
|
166
|
+
Generated documents are not a one-to-one NestJS Swagger compatibility layer. By default, fluo adds `400`, `401`, `403`, `404`, and `500` responses that do not replace explicitly declared responses, and includes the shared `ErrorResponse` schema. Verify the generated error contract before regenerating clients; set `defaultErrorResponsesPolicy: 'omit'` when the legacy document must not receive those default responses.
|
|
167
|
+
|
|
168
|
+
Fluo derives each `operationId` deterministically from the controller tag, handler name, HTTP method, and normalized path. Collisions receive numeric suffixes. If generated clients rely on legacy identifiers, rename the generated operation IDs in `documentTransform` before the document is served, then verify the transformed document with the client generator.
|
|
169
|
+
|
|
170
|
+
With `forRootAsync(...)`, `documentPath` and `uiPath` are outer registration options because their routes are compiled before `useFactory(...)` resolves. Keep those paths beside `inject` and `useFactory`; return only document configuration from the factory. A path returned by the factory cannot reconfigure the already-registered routes.
|
|
104
171
|
|
|
105
172
|
## Public API
|
|
106
173
|
|
|
@@ -109,12 +176,13 @@ Use `OpenApiModule.forRootAsync(...)` when title/version/source configuration co
|
|
|
109
176
|
- `ApiBody`, `ApiParam`, `ApiQuery`, `ApiHeader`, `ApiCookie`: Explicit request-body and parameter documentation decorators that override inferred request documentation when names overlap.
|
|
110
177
|
- `ApiBearerAuth`, `ApiSecurity`: Security requirement decorators.
|
|
111
178
|
- `ApiExcludeEndpoint`: Omit specific handlers from documentation.
|
|
179
|
+
- `ApiOperationOptions`, `ApiResponseOptions`, `ApiParameterOptions`, `ApiBodyOptions`: Decorator option types accepted by `@ApiOperation(...)`, `@ApiResponse(...)`, `@ApiParam(...)`, `@ApiQuery(...)`, `@ApiHeader(...)`, `@ApiCookie(...)`, and `@ApiBody(...)`.
|
|
112
180
|
- `buildOpenApiDocument`: Programmatic document builder (low-level).
|
|
113
181
|
- `OpenApiHandlerRegistry`: Mutable descriptor registry used by advanced integrations to snapshot handler descriptors before document generation.
|
|
114
182
|
- `getControllerTags`, `getMethodApiMetadata`: Metadata readers for advanced tests and integration tooling.
|
|
115
|
-
- `OpenApiModuleOptions`, `OpenApiSwaggerUiAssetsOptions`, `BuildOpenApiDocumentOptions`, `DefaultErrorResponsesPolicy`: Option types for module and builder integrations.
|
|
183
|
+
- `OpenApiModuleOptions`, `OpenApiAsyncModuleOptions`, `OpenApiRouteOptions`, `OpenApiSwaggerUiAssetsOptions`, `BuildOpenApiDocumentOptions`, `DefaultErrorResponsesPolicy`: Option types for module and builder integrations.
|
|
116
184
|
- `OpenApiDocument`, `OpenApiSecuritySchemeObject`, and related OpenAPI shape types: Typed document surface for tests, tooling, and integrations.
|
|
117
|
-
- `OpenApiSchemaObject`: Typed schema surface for explicit `@ApiBody(...)` and `@ApiResponse(...)` schemas, including OpenAPI 3.1 composition (`allOf`, `oneOf`, `anyOf`), object/array constraints, examples/defaults, and read/write/deprecated annotations.
|
|
185
|
+
- `OpenApiSchemaObject`: Typed schema surface for explicit `@ApiBody(...)` and `@ApiResponse(...)` schemas, including OpenAPI 3.1 composition (`allOf`, `oneOf`, `anyOf`), null unions with legacy `nullable` input compatibility, object/array constraints, examples/defaults, and read/write/deprecated annotations.
|
|
118
186
|
|
|
119
187
|
## Related Packages
|
|
120
188
|
|
|
@@ -125,4 +193,5 @@ Use `OpenApiModule.forRootAsync(...)` when title/version/source configuration co
|
|
|
125
193
|
## Example Sources
|
|
126
194
|
|
|
127
195
|
- `packages/openapi/src/openapi-module.test.ts`: Integration tests and usage examples.
|
|
196
|
+
- `packages/openapi/src/openapi-module-routes.test.ts`: Default, custom, multi-document, and route-collision examples.
|
|
128
197
|
- `packages/openapi/src/schema-builder.test.ts`: Document builder and schema generation examples.
|
package/dist/decorators.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Constructor, MetadataPropertyKey } from '@fluojs/core';
|
|
2
2
|
import type { OpenApiSchemaObject } from './schema-builder.js';
|
|
3
3
|
/**
|
|
4
4
|
* User-facing operation metadata accepted by `@ApiOperation(...)`.
|
|
@@ -121,10 +121,11 @@ export declare function ApiTag(tag: string): ClassDecoratorFn;
|
|
|
121
121
|
/**
|
|
122
122
|
* Describe a controller method's OpenAPI operation metadata.
|
|
123
123
|
*
|
|
124
|
-
* @param options Operation metadata
|
|
124
|
+
* @param options Operation metadata; omission or `undefined` uses `{}` without inventing operation fields.
|
|
125
125
|
* @returns A method decorator that stores operation metadata.
|
|
126
|
+
* @remarks An empty write can overwrite earlier stacked operation metadata; it is not equivalent to omitting the decorator.
|
|
126
127
|
*/
|
|
127
|
-
export declare function ApiOperation(options
|
|
128
|
+
export declare function ApiOperation(options?: ApiOperationOptions): MethodDecoratorFn;
|
|
128
129
|
/**
|
|
129
130
|
* Exclude a controller method from generated OpenAPI `paths`.
|
|
130
131
|
*
|
|
@@ -174,10 +175,11 @@ export declare function ApiCookie(name: string, options?: ApiParameterOptions):
|
|
|
174
175
|
/**
|
|
175
176
|
* Declare an explicit request body for a controller method.
|
|
176
177
|
*
|
|
177
|
-
* @param options Request-body metadata
|
|
178
|
+
* @param options Request-body metadata; omission or `undefined` uses `{}` without inventing a schema or required flag.
|
|
178
179
|
* @returns A method decorator that stores request-body metadata.
|
|
180
|
+
* @remarks Empty metadata preserves DTO body inference and emits no body without inference. It can overwrite earlier stacked body metadata.
|
|
179
181
|
*/
|
|
180
|
-
export declare function ApiBody(options
|
|
182
|
+
export declare function ApiBody(options?: ApiBodyOptions): MethodDecoratorFn;
|
|
181
183
|
/**
|
|
182
184
|
* Declare an expected HTTP response for a controller method.
|
|
183
185
|
*
|
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
|
package/dist/decorators.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensureRequestPipelineMetadataSymbol, getRequestPipelineMetadataBag } from '@fluojs/core/request-pipeline';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* User-facing operation metadata accepted by `@ApiOperation(...)`.
|
|
@@ -48,9 +48,9 @@ const openApiMethodRequestBodyKey = Symbol.for('fluo.openapi.method-request-body
|
|
|
48
48
|
const openApiMethodSecurityKey = Symbol.for('fluo.openapi.method-security');
|
|
49
49
|
const openApiMethodSecurityRequirementsKey = Symbol.for('fluo.openapi.method-security-requirements');
|
|
50
50
|
const openApiMethodExcludeEndpointKey = Symbol.for('fluo.openapi.method-exclude-endpoint');
|
|
51
|
-
|
|
51
|
+
ensureRequestPipelineMetadataSymbol();
|
|
52
52
|
function getMetadataBag(target) {
|
|
53
|
-
return
|
|
53
|
+
return getRequestPipelineMetadataBag(target);
|
|
54
54
|
}
|
|
55
55
|
function cloneUnknown(value) {
|
|
56
56
|
if (value === null || value === undefined) {
|
|
@@ -186,10 +186,11 @@ export function ApiTag(tag) {
|
|
|
186
186
|
/**
|
|
187
187
|
* Describe a controller method's OpenAPI operation metadata.
|
|
188
188
|
*
|
|
189
|
-
* @param options Operation metadata
|
|
189
|
+
* @param options Operation metadata; omission or `undefined` uses `{}` without inventing operation fields.
|
|
190
190
|
* @returns A method decorator that stores operation metadata.
|
|
191
|
+
* @remarks An empty write can overwrite earlier stacked operation metadata; it is not equivalent to omitting the decorator.
|
|
191
192
|
*/
|
|
192
|
-
export function ApiOperation(options) {
|
|
193
|
+
export function ApiOperation(options = {}) {
|
|
193
194
|
return (_value, context) => {
|
|
194
195
|
const bag = context.metadata;
|
|
195
196
|
let map = bag[openApiMethodOperationKey];
|
|
@@ -336,10 +337,11 @@ export function ApiCookie(name, options = {}) {
|
|
|
336
337
|
/**
|
|
337
338
|
* Declare an explicit request body for a controller method.
|
|
338
339
|
*
|
|
339
|
-
* @param options Request-body metadata
|
|
340
|
+
* @param options Request-body metadata; omission or `undefined` uses `{}` without inventing a schema or required flag.
|
|
340
341
|
* @returns A method decorator that stores request-body metadata.
|
|
342
|
+
* @remarks Empty metadata preserves DTO body inference and emits no body without inference. It can overwrite earlier stacked body metadata.
|
|
341
343
|
*/
|
|
342
|
-
export function ApiBody(options) {
|
|
344
|
+
export function ApiBody(options = {}) {
|
|
343
345
|
return (_value, context) => {
|
|
344
346
|
const bag = context.metadata;
|
|
345
347
|
let map = bag[openApiMethodRequestBodyKey];
|
package/dist/openapi-module.d.ts
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
|
-
import { type HandlerDescriptor, type HandlerSource } from '@fluojs/http';
|
|
2
1
|
import { type AsyncModuleOptions, type Constructor } from '@fluojs/core';
|
|
2
|
+
import { type HandlerDescriptor, type HandlerSource } from '@fluojs/http';
|
|
3
3
|
import { type ModuleType } from '@fluojs/runtime';
|
|
4
4
|
import { type DefaultErrorResponsesPolicy, type OpenApiDocument, type OpenApiSecuritySchemeObject } from './schema-builder.js';
|
|
5
|
+
import { type OpenApiSwaggerUiAssetsOptions } from './swagger-ui.js';
|
|
6
|
+
export type { OpenApiSwaggerUiAssetsOptions } from './swagger-ui.js';
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
8
|
+
* Routes owned by one `OpenApiModule` registration.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Paths use the normal `@fluojs/http` route grammar and are normalized before
|
|
12
|
+
* registration. The defaults remain `/openapi.json` and `/docs`.
|
|
7
13
|
*/
|
|
8
|
-
export interface
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
export interface OpenApiRouteOptions {
|
|
15
|
+
/** JSON document route. Defaults to `/openapi.json`. */
|
|
16
|
+
readonly documentPath?: string;
|
|
17
|
+
/** Swagger UI route. Defaults to `/docs`. */
|
|
18
|
+
readonly uiPath?: string;
|
|
11
19
|
}
|
|
12
20
|
/**
|
|
13
|
-
* Public options for `OpenApiModule.forRoot(...)
|
|
21
|
+
* Public document and route options for `OpenApiModule.forRoot(...)`.
|
|
14
22
|
*
|
|
15
23
|
* @remarks
|
|
16
24
|
* Keep README examples for full controller/module workflows. These options are
|
|
17
25
|
* intended to document the runtime hooks that shape the generated document.
|
|
18
26
|
*/
|
|
19
|
-
export interface OpenApiModuleOptions {
|
|
27
|
+
export interface OpenApiModuleOptions extends OpenApiRouteOptions {
|
|
20
28
|
defaultErrorResponsesPolicy?: DefaultErrorResponsesPolicy;
|
|
21
29
|
title: string;
|
|
22
30
|
version: string;
|
|
@@ -28,6 +36,14 @@ export interface OpenApiModuleOptions {
|
|
|
28
36
|
extraModels?: Constructor[];
|
|
29
37
|
documentTransform?: (document: OpenApiDocument) => OpenApiDocument;
|
|
30
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Async OpenAPI registration options with routes fixed before module compilation.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* `documentPath` and `uiPath` belong to the outer registration because HTTP
|
|
44
|
+
* routes are compiled before the injected options factory resolves.
|
|
45
|
+
*/
|
|
46
|
+
export type OpenApiAsyncModuleOptions = AsyncModuleOptions<Omit<OpenApiModuleOptions, keyof OpenApiRouteOptions>> & OpenApiRouteOptions;
|
|
31
47
|
/**
|
|
32
48
|
* Runtime module entrypoint for serving OpenAPI JSON and optional Swagger UI.
|
|
33
49
|
*/
|
|
@@ -57,7 +73,9 @@ export declare class OpenApiModule {
|
|
|
57
73
|
* @example
|
|
58
74
|
* ```ts
|
|
59
75
|
* OpenApiModule.forRootAsync({
|
|
76
|
+
* documentPath: '/openapi/internal.json',
|
|
60
77
|
* inject: [ConfigService],
|
|
78
|
+
* uiPath: '/docs/internal',
|
|
61
79
|
* useFactory: (config) => ({
|
|
62
80
|
* title: config.get('APP_NAME'),
|
|
63
81
|
* version: config.get('APP_VERSION'),
|
|
@@ -65,7 +83,7 @@ export declare class OpenApiModule {
|
|
|
65
83
|
* });
|
|
66
84
|
* ```
|
|
67
85
|
*/
|
|
68
|
-
static forRootAsync(options:
|
|
86
|
+
static forRootAsync(options: OpenApiAsyncModuleOptions): ModuleType;
|
|
69
87
|
private static createModule;
|
|
70
88
|
}
|
|
71
89
|
//# sourceMappingURL=openapi-module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-module.d.ts","sourceRoot":"","sources":["../src/openapi-module.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"openapi-module.d.ts","sourceRoot":"","sources":["../src/openapi-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAkD,MAAM,cAAc,CAAC;AACzH,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAGnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,eAAe,EACpB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAEL,KAAK,6BAA6B,EAEnC,MAAM,iBAAiB,CAAC;AAKzB,YAAY,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;IAC9D,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,eAAe,CAAC;CACpE;AAED;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GAAG,kBAAkB,CACxD,IAAI,CAAC,oBAAoB,EAAE,MAAM,mBAAmB,CAAC,CACtD,GAAG,mBAAmB,CAAC;AAgFxB;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU;IASzD;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,yBAAyB,GAAG,UAAU;IAanE,OAAO,CAAC,MAAM,CAAC,YAAY;CAwE5B"}
|