@venizia/ignis-docs 0.0.5 → 0.0.6-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/package.json +1 -1
- package/wiki/best-practices/architecture-decisions.md +0 -8
- package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
- package/wiki/best-practices/performance-optimization.md +3 -3
- package/wiki/best-practices/security-guidelines.md +2 -2
- package/wiki/best-practices/troubleshooting-tips.md +1 -1
- package/wiki/guides/core-concepts/components-guide.md +1 -1
- package/wiki/guides/core-concepts/components.md +2 -2
- package/wiki/guides/core-concepts/dependency-injection.md +1 -1
- package/wiki/guides/core-concepts/services.md +1 -1
- package/wiki/guides/tutorials/building-a-crud-api.md +1 -1
- package/wiki/guides/tutorials/ecommerce-api.md +2 -2
- package/wiki/guides/tutorials/realtime-chat.md +6 -6
- package/wiki/guides/tutorials/testing.md +1 -1
- package/wiki/references/base/bootstrapping.md +0 -2
- package/wiki/references/base/components.md +2 -2
- package/wiki/references/base/controllers.md +0 -1
- package/wiki/references/base/datasources.md +1 -1
- package/wiki/references/base/dependency-injection.md +1 -1
- package/wiki/references/base/filter-system/quick-reference.md +0 -14
- package/wiki/references/base/middlewares.md +0 -8
- package/wiki/references/base/providers.md +0 -9
- package/wiki/references/base/services.md +0 -1
- package/wiki/references/components/authentication/api.md +444 -0
- package/wiki/references/components/authentication/errors.md +177 -0
- package/wiki/references/components/authentication/index.md +571 -0
- package/wiki/references/components/authentication/usage.md +781 -0
- package/wiki/references/components/health-check.md +292 -103
- package/wiki/references/components/index.md +14 -12
- package/wiki/references/components/mail/api.md +505 -0
- package/wiki/references/components/mail/errors.md +176 -0
- package/wiki/references/components/mail/index.md +535 -0
- package/wiki/references/components/mail/usage.md +404 -0
- package/wiki/references/components/request-tracker.md +229 -25
- package/wiki/references/components/socket-io/api.md +1051 -0
- package/wiki/references/components/socket-io/errors.md +119 -0
- package/wiki/references/components/socket-io/index.md +410 -0
- package/wiki/references/components/socket-io/usage.md +322 -0
- package/wiki/references/components/static-asset/api.md +261 -0
- package/wiki/references/components/static-asset/errors.md +89 -0
- package/wiki/references/components/static-asset/index.md +617 -0
- package/wiki/references/components/static-asset/usage.md +364 -0
- package/wiki/references/components/swagger.md +390 -110
- package/wiki/references/components/template/api-page.md +125 -0
- package/wiki/references/components/template/errors-page.md +100 -0
- package/wiki/references/components/template/index.md +104 -0
- package/wiki/references/components/template/setup-page.md +134 -0
- package/wiki/references/components/template/single-page.md +132 -0
- package/wiki/references/components/template/usage-page.md +127 -0
- package/wiki/references/components/websocket/api.md +508 -0
- package/wiki/references/components/websocket/errors.md +123 -0
- package/wiki/references/components/websocket/index.md +453 -0
- package/wiki/references/components/websocket/usage.md +475 -0
- package/wiki/references/helpers/cron/index.md +224 -0
- package/wiki/references/helpers/crypto/index.md +537 -0
- package/wiki/references/helpers/env/index.md +214 -0
- package/wiki/references/helpers/error/index.md +232 -0
- package/wiki/references/helpers/index.md +16 -15
- package/wiki/references/helpers/inversion/index.md +608 -0
- package/wiki/references/helpers/logger/index.md +600 -0
- package/wiki/references/helpers/network/api.md +986 -0
- package/wiki/references/helpers/network/index.md +620 -0
- package/wiki/references/helpers/queue/index.md +589 -0
- package/wiki/references/helpers/redis/index.md +495 -0
- package/wiki/references/helpers/socket-io/api.md +497 -0
- package/wiki/references/helpers/socket-io/index.md +513 -0
- package/wiki/references/helpers/storage/api.md +705 -0
- package/wiki/references/helpers/storage/index.md +583 -0
- package/wiki/references/helpers/template/index.md +66 -0
- package/wiki/references/helpers/template/single-page.md +126 -0
- package/wiki/references/helpers/testing/index.md +510 -0
- package/wiki/references/helpers/types/index.md +512 -0
- package/wiki/references/helpers/uid/index.md +272 -0
- package/wiki/references/helpers/websocket/api.md +736 -0
- package/wiki/references/helpers/websocket/index.md +574 -0
- package/wiki/references/helpers/worker-thread/index.md +470 -0
- package/wiki/references/quick-reference.md +3 -18
- package/wiki/references/utilities/jsx.md +1 -8
- package/wiki/references/utilities/statuses.md +0 -7
- package/wiki/references/components/authentication.md +0 -476
- package/wiki/references/components/mail.md +0 -687
- package/wiki/references/components/socket-io.md +0 -562
- package/wiki/references/components/static-asset.md +0 -1277
- package/wiki/references/helpers/cron.md +0 -108
- package/wiki/references/helpers/crypto.md +0 -132
- package/wiki/references/helpers/env.md +0 -83
- package/wiki/references/helpers/error.md +0 -97
- package/wiki/references/helpers/inversion.md +0 -176
- package/wiki/references/helpers/logger.md +0 -296
- package/wiki/references/helpers/network.md +0 -396
- package/wiki/references/helpers/queue.md +0 -150
- package/wiki/references/helpers/redis.md +0 -142
- package/wiki/references/helpers/socket-io.md +0 -932
- package/wiki/references/helpers/storage.md +0 -665
- package/wiki/references/helpers/testing.md +0 -133
- package/wiki/references/helpers/types.md +0 -167
- package/wiki/references/helpers/uid.md +0 -167
- package/wiki/references/helpers/worker-thread.md +0 -178
|
@@ -1,138 +1,68 @@
|
|
|
1
|
-
# Swagger/OpenAPI
|
|
1
|
+
# Swagger/OpenAPI
|
|
2
2
|
|
|
3
|
-
Automatic interactive API documentation generation using OpenAPI specifications.
|
|
3
|
+
Automatic interactive API documentation generation using OpenAPI specifications, powered by Scalar or Swagger UI.
|
|
4
4
|
|
|
5
5
|
## Quick Reference
|
|
6
6
|
|
|
7
|
-
|
|
|
8
|
-
|
|
9
|
-
| **
|
|
10
|
-
| **
|
|
11
|
-
| **
|
|
12
|
-
|
|
13
|
-
### Default Endpoints
|
|
14
|
-
|
|
15
|
-
| Path | Description |
|
|
16
|
-
|------|-------------|
|
|
17
|
-
| `/doc/explorer` | Documentation UI (Scalar by default) |
|
|
18
|
-
| `/doc/openapi.json` | Raw OpenAPI specification |
|
|
19
|
-
|
|
20
|
-
### UI Provider Types
|
|
7
|
+
| Item | Value |
|
|
8
|
+
|------|-------|
|
|
9
|
+
| **Package** | `@venizia/ignis` |
|
|
10
|
+
| **Class** | `SwaggerComponent` |
|
|
11
|
+
| **UI Factory** | `UIProviderFactory` |
|
|
12
|
+
| **Runtimes** | Both |
|
|
21
13
|
|
|
22
14
|
| Provider | Value | When to Use |
|
|
23
15
|
|----------|-------|-------------|
|
|
24
16
|
| **Scalar** | `'scalar'` | Modern, clean UI (default) |
|
|
25
17
|
| **Swagger UI** | `'swagger'` | Classic Swagger interface |
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **`SwaggerComponent`**: Configures documentation UI and registers routes
|
|
30
|
-
- **`UIProviderFactory`**: Manages different UI providers
|
|
31
|
-
- **`@hono/zod-openapi`**: Powers OpenAPI generation from Zod schemas
|
|
32
|
-
- **Integration**: Works with controller `defineRoute` methods using Zod schemas
|
|
33
|
-
|
|
34
|
-
## Implementation Details
|
|
35
|
-
|
|
36
|
-
### Tech Stack
|
|
37
|
-
|
|
38
|
-
- **Hono**
|
|
39
|
-
- **`@hono/zod-openapi`**
|
|
40
|
-
- **`@hono/swagger-ui`** (for Swagger UI)
|
|
41
|
-
- **`@scalar/hono-api-reference`** (for Scalar UI)
|
|
42
|
-
- **`zod`**
|
|
43
|
-
|
|
44
|
-
### Configuration
|
|
45
|
-
|
|
46
|
-
The Swagger component can be configured via the `ISwaggerOptions` binding. You can customize the documentation path, OpenAPI version, and the UI provider type.
|
|
47
|
-
|
|
48
|
-
**`ISwaggerOptions` Interface:**
|
|
49
|
-
|
|
19
|
+
#### Import Paths
|
|
50
20
|
```typescript
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
base: { path: string }; // Base path for all documentation routes
|
|
54
|
-
doc: { path: string }; // Path to the raw openapi.json file
|
|
55
|
-
ui: {
|
|
56
|
-
path: string; // Path to the documentation UI
|
|
57
|
-
type: 'swagger' | 'scalar'; // Type of UI to render
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
explorer: {
|
|
61
|
-
openapi: string;
|
|
62
|
-
info?: { /* ... */ };
|
|
63
|
-
servers?: Array<{ url: string; description?: string; }>;
|
|
64
|
-
};
|
|
65
|
-
uiConfig?: Record<string, any>; // Custom config for the UI provider
|
|
66
|
-
}
|
|
21
|
+
import { SwaggerComponent, SwaggerBindingKeys, UIProviderFactory } from '@venizia/ignis';
|
|
22
|
+
import type { ISwaggerOptions, IUIProvider, IUIConfig, IGetProviderParams } from '@venizia/ignis';
|
|
67
23
|
```
|
|
68
24
|
|
|
69
|
-
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
### Step 1: Bind Configuration (Optional)
|
|
70
28
|
|
|
71
|
-
|
|
29
|
+
Skip this step to use the defaults (Scalar UI at `/doc/explorer`). To customize:
|
|
72
30
|
|
|
73
31
|
```typescript
|
|
74
|
-
|
|
32
|
+
// In your Application class's preConfigure method (src/application.ts)
|
|
33
|
+
import { SwaggerBindingKeys, ISwaggerOptions } from '@venizia/ignis';
|
|
34
|
+
|
|
35
|
+
this.bind<ISwaggerOptions>({
|
|
36
|
+
key: SwaggerBindingKeys.SWAGGER_OPTIONS,
|
|
37
|
+
}).toValue({
|
|
75
38
|
restOptions: {
|
|
76
39
|
base: { path: '/doc' },
|
|
77
40
|
doc: { path: '/openapi.json' },
|
|
78
|
-
ui: { path: '/explorer', type: '
|
|
41
|
+
ui: { path: '/explorer', type: 'swagger' }, // Use Swagger UI instead of Scalar
|
|
79
42
|
},
|
|
80
|
-
|
|
81
|
-
|
|
43
|
+
explorer: {
|
|
44
|
+
openapi: '3.0.0',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
82
47
|
```
|
|
83
48
|
|
|
84
|
-
###
|
|
85
|
-
|
|
86
|
-
#### 1. Registering the Swagger Component
|
|
87
|
-
|
|
88
|
-
In your `src/application.ts`, register the `SwaggerComponent`.
|
|
49
|
+
### Step 2: Register Component
|
|
89
50
|
|
|
90
51
|
```typescript
|
|
91
52
|
// src/application.ts
|
|
92
53
|
import { SwaggerComponent, BaseApplication, ValueOrPromise } from '@venizia/ignis';
|
|
93
54
|
|
|
94
55
|
export class Application extends BaseApplication {
|
|
95
|
-
// ...
|
|
96
|
-
preConfigure(): ValueOrPromise<void> {
|
|
97
|
-
// ...
|
|
98
|
-
this.component(SwaggerComponent);
|
|
99
|
-
// ...
|
|
100
|
-
}
|
|
101
|
-
// ...
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
#### 2. Customizing the UI Provider
|
|
106
|
-
|
|
107
|
-
To change the UI provider to Swagger UI, you can bind custom options in your application's `preConfigure` method.
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
import { SwaggerComponent, SwaggerBindingKeys, ISwaggerOptions } from '@venizia/ignis';
|
|
111
|
-
|
|
112
|
-
// ... in your Application class's preConfigure method
|
|
113
56
|
preConfigure(): ValueOrPromise<void> {
|
|
114
57
|
// ...
|
|
115
|
-
this.bind<ISwaggerOptions>({
|
|
116
|
-
key: SwaggerBindingKeys.SWAGGER_OPTIONS,
|
|
117
|
-
}).toValue({
|
|
118
|
-
restOptions: {
|
|
119
|
-
base: { path: '/doc' },
|
|
120
|
-
doc: { path: '/openapi.json' },
|
|
121
|
-
ui: { path: '/explorer', type: 'swagger' }, // Use Swagger UI
|
|
122
|
-
},
|
|
123
|
-
explorer: {
|
|
124
|
-
openapi: '3.0.0',
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
|
|
128
58
|
this.component(SwaggerComponent);
|
|
129
|
-
// ...
|
|
130
59
|
}
|
|
60
|
+
}
|
|
131
61
|
```
|
|
132
62
|
|
|
133
|
-
|
|
63
|
+
### Step 3: Define Routes with Zod Schemas
|
|
134
64
|
|
|
135
|
-
To get the most out of the documentation, define your routes with `zod` schemas
|
|
65
|
+
To get the most out of the documentation, define your routes with `zod` schemas:
|
|
136
66
|
|
|
137
67
|
```typescript
|
|
138
68
|
// src/controllers/hello.controller.ts
|
|
@@ -165,28 +95,378 @@ export class HelloController extends BaseController {
|
|
|
165
95
|
}
|
|
166
96
|
```
|
|
167
97
|
|
|
168
|
-
|
|
98
|
+
> [!TIP]
|
|
99
|
+
> Controllers using `defineRoute` with Zod schemas automatically generate OpenAPI specs. The Swagger component discovers all registered controller routes and renders them in the documentation UI.
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
| Option | Type | Default | Description |
|
|
104
|
+
|--------|------|---------|-------------|
|
|
105
|
+
| `restOptions.base.path` | `string` | `'/doc'` | Base path for all documentation routes |
|
|
106
|
+
| `restOptions.doc.path` | `string` | `'/openapi.json'` | Path to the raw OpenAPI spec (relative to base) |
|
|
107
|
+
| `restOptions.ui.path` | `string` | `'/explorer'` | Path to the documentation UI (relative to base) |
|
|
108
|
+
| `restOptions.ui.type` | `'swagger' \| 'scalar'` | `'scalar'` | UI provider type |
|
|
109
|
+
| `explorer.openapi` | `string` | `'3.0.0'` | OpenAPI specification version |
|
|
110
|
+
| `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed to the UI provider |
|
|
111
|
+
|
|
112
|
+
> [!IMPORTANT]
|
|
113
|
+
> The `explorer.info` field is **always overwritten** during the component's `binding()` phase. The component unconditionally reads your application's `package.json` via `application.getAppInfo()` and sets `explorer.info` to `{ title, version, description, contact }` from that data. Any user-provided `explorer.info` values are discarded. If you need to customize these fields, update your `package.json` instead.
|
|
114
|
+
|
|
115
|
+
> [!NOTE]
|
|
116
|
+
> The `explorer.servers` field is auto-populated only when empty. If you provide `explorer.servers` with at least one entry, the component preserves your values. When no servers are configured, it creates a default entry from `application.getServerAddress()` plus the application base path.
|
|
117
|
+
|
|
118
|
+
#### ISwaggerOptions -- Full Reference
|
|
119
|
+
```typescript
|
|
120
|
+
export interface ISwaggerOptions {
|
|
121
|
+
restOptions: {
|
|
122
|
+
base: { path: string };
|
|
123
|
+
doc: { path: string };
|
|
124
|
+
ui: { path: string; type: TDocumentUIType };
|
|
125
|
+
};
|
|
126
|
+
explorer: {
|
|
127
|
+
openapi: string;
|
|
128
|
+
info?: {
|
|
129
|
+
title: string;
|
|
130
|
+
version: string;
|
|
131
|
+
description: string;
|
|
132
|
+
contact?: { name: string; email: string };
|
|
133
|
+
};
|
|
134
|
+
servers?: Array<{
|
|
135
|
+
url: string;
|
|
136
|
+
description?: string;
|
|
137
|
+
}>;
|
|
138
|
+
};
|
|
139
|
+
uiConfig?: Record<string, any>;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Option | Type | Default | Description |
|
|
144
|
+
|--------|------|---------|-------------|
|
|
145
|
+
| `restOptions.base.path` | `string` | `'/doc'` | Base path for all documentation routes |
|
|
146
|
+
| `restOptions.doc.path` | `string` | `'/openapi.json'` | Path to the raw OpenAPI spec (relative to base) |
|
|
147
|
+
| `restOptions.ui.path` | `string` | `'/explorer'` | Path to the documentation UI (relative to base) |
|
|
148
|
+
| `restOptions.ui.type` | `'swagger' \| 'scalar'` | `'scalar'` | UI provider type |
|
|
149
|
+
| `explorer.openapi` | `string` | `'3.0.0'` | OpenAPI specification version |
|
|
150
|
+
| `explorer.info.title` | `string` | Always from `package.json` `name` | API title (overwritten at runtime) |
|
|
151
|
+
| `explorer.info.version` | `string` | Always from `package.json` `version` | API version (overwritten at runtime) |
|
|
152
|
+
| `explorer.info.description` | `string` | Always from `package.json` `description` | API description (overwritten at runtime) |
|
|
153
|
+
| `explorer.info.contact` | `{ name, email }` | Always from `package.json` `author` | Contact information (overwritten at runtime) |
|
|
154
|
+
| `explorer.servers` | `Array<{ url, description? }>` | Auto-detected when empty | Server URLs |
|
|
155
|
+
| `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed to the UI provider |
|
|
156
|
+
|
|
157
|
+
#### IGetProviderParams Interface
|
|
158
|
+
|
|
159
|
+
The `IGetProviderParams` interface is used by `UIProviderFactory.getProvider()` and `UIProviderFactory.register()`:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
export interface IGetProviderParams {
|
|
163
|
+
type: string;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This interface is exported for use when building custom tooling around the `UIProviderFactory` -- for example, programmatically querying which providers are available or registering providers in tests.
|
|
168
|
+
|
|
169
|
+
### Tech Stack
|
|
170
|
+
|
|
171
|
+
| Library | Purpose |
|
|
172
|
+
|---------|---------|
|
|
173
|
+
| `@hono/zod-openapi` | OpenAPI generation from Zod schemas |
|
|
174
|
+
| `@hono/swagger-ui` | Swagger UI rendering |
|
|
175
|
+
| `@scalar/hono-api-reference` | Scalar UI rendering |
|
|
176
|
+
| `zod` | Schema validation and type generation |
|
|
177
|
+
|
|
178
|
+
> [!TIP]
|
|
179
|
+
> The component also auto-registers JWT (`bearer`) and Basic security schemes in the OpenAPI spec, so authenticated endpoints display the correct auth UI in the documentation.
|
|
180
|
+
|
|
181
|
+
## Architecture
|
|
182
|
+
|
|
183
|
+
### Component Lifecycle
|
|
184
|
+
|
|
185
|
+
The `SwaggerComponent` executes the following during `binding()`:
|
|
186
|
+
|
|
187
|
+
1. **Resolve options** -- reads `SwaggerBindingKeys.SWAGGER_OPTIONS` from DI using `application.get()` with `isOptional: true`, falls back to `DEFAULT_SWAGGER_OPTIONS` via the `??` operator if no binding exists
|
|
188
|
+
2. **Overwrite info** -- unconditionally reads `package.json` via `application.getAppInfo()` and overwrites `explorer.info` with `{ title: appInfo.name, version: appInfo.version, description: appInfo.description, contact: appInfo.author }`
|
|
189
|
+
3. **Auto-detect servers** -- if `explorer.servers` is empty or unset, creates one entry from `http://` + `application.getServerAddress()` + `configs.path.base`
|
|
190
|
+
4. **Normalize paths** -- all path segments (`base.path`, `doc.path`, `ui.path`) are normalized to ensure a leading `/` is present, handling both `/path` and `path` inputs
|
|
191
|
+
5. **Register OpenAPI doc route** -- calls `rootRouter.doc(docPath, explorer)` to register the raw JSON endpoint
|
|
192
|
+
6. **Resolve UI type with fallback** -- evaluates `restOptions.ui.type || DocumentUITypes.SWAGGER`. Note: this means a falsy value (empty string) falls back to `'swagger'`, not `'scalar'`
|
|
193
|
+
7. **Validate UI type** -- checks the resolved type against `DocumentUITypes.SCHEME_SET`, throws if invalid
|
|
194
|
+
8. **Register UI provider** -- calls `UIProviderFactory.register({ type })` to instantiate the UI renderer
|
|
195
|
+
9. **Construct docUrl** -- builds the full documentation URL by joining `configs.path.base`, `configs.basePath`, and the computed `docPath`
|
|
196
|
+
10. **Register UI route** -- creates `GET` handler at `uiPath` that calls `uiProvider.render()` with `{ title: appInfo.name, url: docUrl, ...uiConfig }`
|
|
197
|
+
11. **Register security schemes** -- auto-registers JWT (bearer) and Basic security schemes in the OpenAPI registry
|
|
198
|
+
|
|
199
|
+
### Architecture Components
|
|
200
|
+
|
|
201
|
+
| Component | Class | Role |
|
|
202
|
+
|-----------|-------|------|
|
|
203
|
+
| **SwaggerComponent** | `extends BaseComponent` | Orchestrates binding, overwrites OpenAPI metadata from `package.json` |
|
|
204
|
+
| **UIProviderFactory** | `extends MemoryStorageHelper` (singleton) | Registry for UI providers, validates and instantiates |
|
|
205
|
+
| **SwaggerUIProvider** | `implements IUIProvider` | Renders Swagger UI via `@hono/swagger-ui` |
|
|
206
|
+
| **ScalarUIProvider** | `implements IUIProvider` | Renders Scalar UI via `@scalar/hono-api-reference` |
|
|
207
|
+
|
|
208
|
+
#### UIProviderFactory and MemoryStorageHelper
|
|
209
|
+
|
|
210
|
+
`UIProviderFactory` extends `MemoryStorageHelper<{ [key: string | symbol]: IUIProvider }>`, which provides a simple in-memory key-value store with the following methods used internally:
|
|
211
|
+
|
|
212
|
+
- `isBound(key)` -- checks if a provider type is already registered
|
|
213
|
+
- `get(key)` -- retrieves a registered provider instance
|
|
214
|
+
- `set(key, value)` -- stores a provider instance
|
|
215
|
+
- `keys()` -- lists all registered provider type keys
|
|
216
|
+
|
|
217
|
+
This gives the factory a lightweight, type-safe storage backend without requiring the full DI container.
|
|
218
|
+
|
|
219
|
+
#### Lazy Dynamic Imports
|
|
220
|
+
|
|
221
|
+
Both `SwaggerUIProvider` and `ScalarUIProvider` use `await import()` inside their `render()` method to load the underlying UI library:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// SwaggerUIProvider
|
|
225
|
+
async render(context, config, next) {
|
|
226
|
+
const { swaggerUI } = await import('@hono/swagger-ui');
|
|
227
|
+
// ...
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ScalarUIProvider
|
|
231
|
+
async render(context, config, next) {
|
|
232
|
+
const { Scalar } = await import('@scalar/hono-api-reference');
|
|
233
|
+
// ...
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
This means UI libraries are loaded on the **first HTTP request** to the documentation endpoint, not at application startup. This keeps startup time fast and avoids loading unused UI libraries (only the configured provider's library is ever imported).
|
|
238
|
+
|
|
239
|
+
#### ScalarUIProvider Title Mapping
|
|
240
|
+
|
|
241
|
+
The `ScalarUIProvider` maps the `title` field to `pageTitle` when calling the Scalar renderer:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
const { title, url, ...customConfig } = config;
|
|
245
|
+
return Scalar({ url, pageTitle: title, ...customConfig })(context, next);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
This is a quirk to be aware of if you are inspecting the rendered output or writing custom UI providers -- Scalar uses `pageTitle` instead of `title`.
|
|
249
|
+
|
|
250
|
+
### UIProviderFactory API
|
|
251
|
+
|
|
252
|
+
| Method | Signature | Description |
|
|
253
|
+
|--------|-----------|-------------|
|
|
254
|
+
| `getInstance()` | `static () => UIProviderFactory` | Returns singleton instance |
|
|
255
|
+
| `register()` | `(opts: { type: string }) => void` | Instantiates and registers a UI provider (idempotent) |
|
|
256
|
+
| `getProvider()` | `(opts: IGetProviderParams) => IUIProvider` | Returns registered provider or throws |
|
|
257
|
+
| `getRegisteredProviders()` | `() => string[]` | Lists all registered provider type keys |
|
|
258
|
+
|
|
259
|
+
#### register() Idempotency
|
|
260
|
+
|
|
261
|
+
The `register()` method is idempotent. If a provider of the given type is already registered, it logs a warning and returns without error:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
register(opts: { type: string }): void {
|
|
265
|
+
if (this.isBound(opts.type)) {
|
|
266
|
+
this.logger
|
|
267
|
+
.for(this.register.name)
|
|
268
|
+
.warn('Skip registering BOUNDED Document UI | type: %s', opts.type);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// ... instantiate and store the provider
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
This means calling `register({ type: 'scalar' })` multiple times is safe and will not create duplicate provider instances.
|
|
276
|
+
|
|
277
|
+
### IUIProvider Interface
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
interface IUIProvider {
|
|
281
|
+
render(context: Context, config: IUIConfig, next: Next): Promise<Response | void>;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
interface IUIConfig {
|
|
285
|
+
title: string; // App name from package.json
|
|
286
|
+
url: string; // Full URL to OpenAPI JSON endpoint
|
|
287
|
+
[key: string]: any; // Additional config from uiConfig option
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Security Scheme Registration
|
|
292
|
+
|
|
293
|
+
The component auto-registers two OpenAPI security schemes:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// JWT Bearer
|
|
297
|
+
rootRouter.openAPIRegistry.registerComponent('securitySchemes', 'jwt', {
|
|
298
|
+
type: 'http',
|
|
299
|
+
scheme: 'bearer',
|
|
300
|
+
bearerFormat: 'JWT',
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Basic Auth
|
|
304
|
+
rootRouter.openAPIRegistry.registerComponent('securitySchemes', 'basic', {
|
|
305
|
+
type: 'http',
|
|
306
|
+
scheme: 'basic',
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
This ensures routes using `authStrategies: ['jwt']` or `authStrategies: ['basic']` display the correct auth UI (lock icon + input fields) in the documentation.
|
|
311
|
+
|
|
312
|
+
## Binding Keys
|
|
313
|
+
|
|
314
|
+
| Key | Constant | Type | Required | Default |
|
|
315
|
+
|-----|----------|------|----------|---------|
|
|
316
|
+
| `@app/swagger/options` | `SwaggerBindingKeys.SWAGGER_OPTIONS` | `ISwaggerOptions` | No | See below |
|
|
317
|
+
|
|
318
|
+
The `SwaggerComponent` constructor creates a default binding using the `Binding` fluent API:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
this.bindings = {
|
|
322
|
+
[SwaggerBindingKeys.SWAGGER_OPTIONS]: Binding.bind<ISwaggerOptions>({
|
|
323
|
+
key: SwaggerBindingKeys.SWAGGER_OPTIONS,
|
|
324
|
+
}).toValue(DEFAULT_SWAGGER_OPTIONS),
|
|
325
|
+
};
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Note that unlike `HealthCheckComponent`, `SwaggerComponent` does not pass `initDefault: { enable: true, container: application }` to `BaseComponent`. The default bindings stored in `this.bindings` are not automatically registered into the DI container. Instead, the `binding()` method reads from the container with `isOptional: true` and falls back to `DEFAULT_SWAGGER_OPTIONS` via the `??` operator.
|
|
329
|
+
|
|
330
|
+
**Default value:**
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
const DEFAULT_SWAGGER_OPTIONS: ISwaggerOptions = {
|
|
334
|
+
restOptions: {
|
|
335
|
+
base: { path: '/doc' },
|
|
336
|
+
doc: { path: '/openapi.json' },
|
|
337
|
+
ui: { path: '/explorer', type: 'scalar' },
|
|
338
|
+
},
|
|
339
|
+
explorer: {
|
|
340
|
+
openapi: '3.0.0',
|
|
341
|
+
info: {
|
|
342
|
+
title: 'API Documentation',
|
|
343
|
+
version: '1.0.0',
|
|
344
|
+
description: 'API documentation for your service',
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
> [!NOTE]
|
|
351
|
+
> The `explorer.info` values in `DEFAULT_SWAGGER_OPTIONS` are never used at runtime because `binding()` unconditionally overwrites `explorer.info` with data from `package.json`. They exist only as structural defaults.
|
|
352
|
+
|
|
353
|
+
### Type Definitions
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
type TDocumentUIType = TConstValue<typeof DocumentUITypes>;
|
|
357
|
+
|
|
358
|
+
class DocumentUITypes {
|
|
359
|
+
static readonly SWAGGER = 'swagger';
|
|
360
|
+
static readonly SCALAR = 'scalar';
|
|
361
|
+
static readonly SCHEME_SET: Set<string>;
|
|
362
|
+
static isValid(input: string): boolean;
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
`TDocumentUIType` is derived via `TConstValue`, which extracts the union of all `static readonly` string values from `DocumentUITypes`. This ensures the type stays in sync with the constants automatically.
|
|
367
|
+
|
|
368
|
+
## API Endpoints
|
|
369
|
+
|
|
370
|
+
| Method | Path | Description |
|
|
371
|
+
|--------|------|-------------|
|
|
372
|
+
| `GET` | `/doc/explorer` | Documentation UI (Scalar by default) |
|
|
373
|
+
| `GET` | `/doc/openapi.json` | Raw OpenAPI specification |
|
|
374
|
+
|
|
375
|
+
> [!NOTE]
|
|
376
|
+
> These paths are based on the default configuration. If you customize `restOptions.base.path`, `restOptions.ui.path`, or `restOptions.doc.path`, the actual endpoints change accordingly.
|
|
377
|
+
|
|
378
|
+
### Documentation UI Endpoint
|
|
379
|
+
|
|
380
|
+
**Default path:** `/doc/explorer`
|
|
381
|
+
|
|
382
|
+
Renders an interactive API documentation page using the configured UI provider (Scalar or Swagger UI). The UI fetches the OpenAPI spec from the JSON endpoint and renders it with full request/response exploration, authentication controls, and try-it-out functionality.
|
|
383
|
+
|
|
384
|
+
### OpenAPI JSON Endpoint
|
|
385
|
+
|
|
386
|
+
**Default path:** `/doc/openapi.json`
|
|
387
|
+
|
|
388
|
+
Returns the raw OpenAPI JSON specification generated from all registered controller routes and their Zod schemas. This endpoint can be used by:
|
|
389
|
+
- External API testing tools (Postman, Insomnia)
|
|
390
|
+
- CI pipelines for API contract validation
|
|
391
|
+
- Client SDK generators (openapi-generator, orval)
|
|
392
|
+
- API gateway configuration
|
|
393
|
+
|
|
394
|
+
## Troubleshooting
|
|
395
|
+
|
|
396
|
+
### "Invalid document UI Type"
|
|
397
|
+
|
|
398
|
+
**Cause:** The `restOptions.ui.type` value is not `'swagger'` or `'scalar'`. The `UIProviderFactory` only recognizes these two built-in providers. Note that a falsy value (empty string, `undefined`) does not trigger this error -- it silently falls back to `'swagger'` due to the `||` operator, not to the default `'scalar'`.
|
|
399
|
+
|
|
400
|
+
**Fix:** Use a valid UI type:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
this.bind<ISwaggerOptions>({
|
|
404
|
+
key: SwaggerBindingKeys.SWAGGER_OPTIONS,
|
|
405
|
+
}).toValue({
|
|
406
|
+
restOptions: {
|
|
407
|
+
base: { path: '/doc' },
|
|
408
|
+
doc: { path: '/openapi.json' },
|
|
409
|
+
ui: { path: '/explorer', type: 'scalar' }, // 'scalar' or 'swagger'
|
|
410
|
+
},
|
|
411
|
+
explorer: { openapi: '3.0.0' },
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Documentation UI shows no routes
|
|
416
|
+
|
|
417
|
+
**Cause:** Controllers are not defining routes with Zod schemas via `defineRoute` or `bindRoute`. Only routes registered through `@hono/zod-openapi` appear in the OpenAPI spec.
|
|
418
|
+
|
|
419
|
+
**Fix:** Use `defineRoute` with Zod response schemas in your controllers:
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
this.defineRoute({
|
|
423
|
+
configs: {
|
|
424
|
+
path: '/',
|
|
425
|
+
method: 'get',
|
|
426
|
+
responses: {
|
|
427
|
+
200: jsonContent({
|
|
428
|
+
description: 'Success',
|
|
429
|
+
schema: z.object({ message: z.string() }),
|
|
430
|
+
}),
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
handler: (c) => c.json({ message: 'ok' }, 200),
|
|
434
|
+
});
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### "Unknown UI Provider"
|
|
438
|
+
|
|
439
|
+
**Cause:** The `UIProviderFactory.getProvider()` was called with a type that has not been registered. This typically happens if the component binding phase failed silently.
|
|
440
|
+
|
|
441
|
+
**Fix:** Ensure the `SwaggerComponent` is registered in `preConfigure()` and that no errors occur during its `binding()` phase. Check the application logs for warnings from `UIProviderFactory`.
|
|
442
|
+
|
|
443
|
+
### OpenAPI spec missing authentication schemes
|
|
444
|
+
|
|
445
|
+
**Cause:** The `SwaggerComponent` auto-registers JWT and Basic security schemes. If the `AuthenticationComponent` is not registered, authenticated routes will not show auth UI in the documentation.
|
|
446
|
+
|
|
447
|
+
**Fix:** Register `AuthenticationComponent` before `SwaggerComponent` in `preConfigure()` to ensure auth strategies are available when the Swagger component configures security schemes.
|
|
169
448
|
|
|
170
|
-
|
|
449
|
+
### explorer.info values not matching custom configuration
|
|
171
450
|
|
|
172
|
-
|
|
173
|
-
- **/doc/openapi.json**: The raw OpenAPI specification.
|
|
451
|
+
**Cause:** The `SwaggerComponent` unconditionally overwrites `explorer.info` with values from `package.json` during its `binding()` phase. Any values you set in `explorer.info` via the DI binding are discarded.
|
|
174
452
|
|
|
175
|
-
|
|
453
|
+
**Fix:** Update your project's `package.json` fields (`name`, `version`, `description`, `author`) to control what appears in the API documentation info section. The component reads these via `application.getAppInfo()`.
|
|
176
454
|
|
|
177
455
|
## See Also
|
|
178
456
|
|
|
179
|
-
- **
|
|
457
|
+
- **Guides:**
|
|
180
458
|
- [Components Overview](/guides/core-concepts/components) - Component system basics
|
|
181
459
|
- [Controllers](/guides/core-concepts/controllers) - Defining OpenAPI routes
|
|
182
460
|
|
|
183
|
-
- **
|
|
184
|
-
- [Components
|
|
461
|
+
- **Components:**
|
|
462
|
+
- [All Components](./index) - Built-in components list
|
|
463
|
+
- [Authentication](./authentication/) - JWT/Basic auth for secured endpoints
|
|
185
464
|
|
|
186
|
-
- **
|
|
465
|
+
- **Utilities:**
|
|
187
466
|
- [Schema Utilities](/references/utilities/schema) - Response schema helpers
|
|
188
467
|
- [JSX Utilities](/references/utilities/jsx) - HTML response schemas
|
|
189
468
|
|
|
190
469
|
- **External Resources:**
|
|
191
470
|
- [OpenAPI Specification](https://swagger.io/specification/) - OpenAPI standard
|
|
192
|
-
- [Scalar Documentation](https://github.com/scalar/scalar) - API documentation UI
|
|
471
|
+
- [Scalar Documentation](https://github.com/scalar/scalar) - Scalar API documentation UI
|
|
472
|
+
- [@hono/zod-openapi](https://github.com/honojs/middleware/tree/main/packages/zod-openapi) - Hono OpenAPI integration
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# API Reference Page Template (Tier 2 -- api.md)
|
|
2
|
+
|
|
3
|
+
The "understand it deeply" page. A developer reads this on Day 30 when they need to understand how the component works internally, debug edge cases, or extend behavior. Contains architecture diagrams, full method signatures, internal lifecycle, and type definitions.
|
|
4
|
+
|
|
5
|
+
Paired with [Setup](./setup-page), [Usage](./usage-page), and [Error Reference](./errors-page).
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
Always created alongside the other 3 pages for Tier 2 components.
|
|
10
|
+
|
|
11
|
+
## Page Structure
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
# {Component Name} -- API Reference
|
|
15
|
+
|
|
16
|
+
> Architecture, method signatures, and internals for the [{Component Name}](./) component.
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
` ``
|
|
21
|
+
┌─────────────────┐
|
|
22
|
+
│ Application │
|
|
23
|
+
└────────┬────────┘
|
|
24
|
+
│ registers
|
|
25
|
+
▼
|
|
26
|
+
┌─────────────────┐ ┌──────────────┐
|
|
27
|
+
│ Component │────▶│ Helper │
|
|
28
|
+
└─────────────────┘ └──────────────┘
|
|
29
|
+
` ``
|
|
30
|
+
|
|
31
|
+
### {Flow Name} (e.g., "Authentication Flow", "Message Delivery Flow")
|
|
32
|
+
|
|
33
|
+
1. Step-by-step explanation of the data flow
|
|
34
|
+
2. What happens at each stage
|
|
35
|
+
3. How components interact
|
|
36
|
+
|
|
37
|
+
## {Public API Section} (e.g., "Server Helper API", "Strategy Registry")
|
|
38
|
+
|
|
39
|
+
### `methodName()`
|
|
40
|
+
|
|
41
|
+
` ``typescript
|
|
42
|
+
methodName(opts: { param: Type }): ReturnType
|
|
43
|
+
` ``
|
|
44
|
+
|
|
45
|
+
| Parameter | Type | Description |
|
|
46
|
+
|-----------|------|-------------|
|
|
47
|
+
| `param` | `Type` | What it controls |
|
|
48
|
+
|
|
49
|
+
**Returns:** Description of return value.
|
|
50
|
+
|
|
51
|
+
### `anotherMethod()`
|
|
52
|
+
|
|
53
|
+
` ``typescript
|
|
54
|
+
anotherMethod(): void
|
|
55
|
+
` ``
|
|
56
|
+
|
|
57
|
+
Description of what this method does.
|
|
58
|
+
|
|
59
|
+
## Types Reference
|
|
60
|
+
|
|
61
|
+
### `IInterfaceName`
|
|
62
|
+
|
|
63
|
+
` ``typescript
|
|
64
|
+
interface IInterfaceName {
|
|
65
|
+
field: string;
|
|
66
|
+
optional?: number;
|
|
67
|
+
}
|
|
68
|
+
` ``
|
|
69
|
+
|
|
70
|
+
| Field | Type | Description |
|
|
71
|
+
|-------|------|-------------|
|
|
72
|
+
| `field` | `string` | What it represents |
|
|
73
|
+
| `optional` | `number` | Optional description |
|
|
74
|
+
|
|
75
|
+
## Internals
|
|
76
|
+
|
|
77
|
+
### Component Lifecycle
|
|
78
|
+
|
|
79
|
+
How the component initializes during application startup:
|
|
80
|
+
|
|
81
|
+
1. **`constructor()`** -- What happens at instantiation
|
|
82
|
+
2. **`binding()`** -- What gets registered with the DI container
|
|
83
|
+
3. **`resolveBindings()`** -- How bindings are resolved
|
|
84
|
+
4. **Post-start hook** -- What runs after the server starts (if applicable)
|
|
85
|
+
|
|
86
|
+
### {Internal Mechanism} (e.g., "Token Encryption", "Redis Channel Architecture")
|
|
87
|
+
|
|
88
|
+
Detailed explanation of a key internal mechanism.
|
|
89
|
+
|
|
90
|
+
` ``typescript
|
|
91
|
+
// Key implementation code
|
|
92
|
+
` ``
|
|
93
|
+
|
|
94
|
+
### {Another Internal}
|
|
95
|
+
|
|
96
|
+
Description and code.
|
|
97
|
+
|
|
98
|
+
## See Also
|
|
99
|
+
|
|
100
|
+
- [Setup & Configuration](./) -- Quick reference, setup steps, configuration options
|
|
101
|
+
- [Usage & Examples](./usage) -- Usage patterns, examples, API endpoints
|
|
102
|
+
- [Error Reference](./errors) -- Error tables and troubleshooting
|
|
103
|
+
|
|
104
|
+
- **Guides:**
|
|
105
|
+
- [Components](/guides/core-concepts/components) - Component system overview
|
|
106
|
+
|
|
107
|
+
- **Components:**
|
|
108
|
+
- [All Components](../index) - Built-in components list
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Rules
|
|
112
|
+
|
|
113
|
+
- **File name:** Always `api.md` inside the component directory
|
|
114
|
+
- **Focus:** How it works internally. Architecture, methods, types, lifecycle
|
|
115
|
+
- **Architecture section:** Required. Use ASCII art or Mermaid diagrams. Focus on data flow and component relationships
|
|
116
|
+
- **Method signatures:** Show full TypeScript signatures with parameter tables
|
|
117
|
+
- **Types Reference:** Include all public interfaces and types. Show the full interface definition plus a field description table
|
|
118
|
+
- **Internals:** Explain the component lifecycle and key internal mechanisms. Include relevant source code snippets
|
|
119
|
+
- **No setup steps** on this page -- those are in `index.md`
|
|
120
|
+
- **No usage examples** on this page -- those are in `usage.md`
|
|
121
|
+
- **No API endpoint specs** on this page -- those are in `usage.md`
|
|
122
|
+
- **No error tables** on this page -- those are in `errors.md`
|
|
123
|
+
- **No troubleshooting** on this page -- those are in `errors.md`
|
|
124
|
+
- **No collapsible sections** -- show all content directly using `####` sub-headings for source code, verbose explanations
|
|
125
|
+
- Use `> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`, `> [!IMPORTANT]` callouts
|