@venizia/ignis-docs 0.2.0 → 0.2.1-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 +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +22 -11
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +6 -2
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +182 -93
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +107 -322
- package/content/extensions/components/authentication/api.md +454 -603
- package/content/extensions/components/authentication/errors.md +121 -498
- package/content/extensions/components/authentication/index.md +88 -801
- package/content/extensions/components/authentication/usage.md +207 -956
- package/content/extensions/components/authorization/api.md +736 -656
- package/content/extensions/components/authorization/errors.md +168 -206
- package/content/extensions/components/authorization/index.md +82 -797
- package/content/extensions/components/authorization/usage.md +194 -527
- package/content/extensions/components/health-check.md +71 -243
- package/content/extensions/components/mail/api.md +504 -287
- package/content/extensions/components/mail/errors.md +73 -61
- package/content/extensions/components/mail/index.md +96 -467
- package/content/extensions/components/mail/usage.md +130 -172
- package/content/extensions/components/request-tracker.md +66 -173
- package/content/extensions/components/socket-io/api.md +195 -13
- package/content/extensions/components/socket-io/errors.md +3 -3
- package/content/extensions/components/socket-io/index.md +50 -337
- package/content/extensions/components/socket-io/usage.md +143 -26
- package/content/extensions/components/static-asset/api.md +410 -142
- package/content/extensions/components/static-asset/errors.md +110 -53
- package/content/extensions/components/static-asset/index.md +79 -608
- package/content/extensions/components/static-asset/usage.md +180 -300
- package/content/extensions/components/websocket/api.md +275 -399
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +74 -407
- package/content/extensions/components/websocket/usage.md +110 -341
- package/content/extensions/helpers/cron/index.md +51 -160
- package/content/extensions/helpers/crypto/index.md +62 -483
- package/content/extensions/helpers/crypto/reference.md +456 -0
- package/content/extensions/helpers/env/index.md +60 -178
- package/content/extensions/helpers/error/index.md +221 -207
- package/content/extensions/helpers/inversion/index.md +65 -556
- package/content/extensions/helpers/inversion/reference.md +522 -0
- package/content/extensions/helpers/kafka/admin.md +20 -1
- package/content/extensions/helpers/kafka/compile-binary.md +41 -35
- package/content/extensions/helpers/kafka/consumer.md +54 -20
- package/content/extensions/helpers/kafka/examples.md +21 -16
- package/content/extensions/helpers/kafka/index.md +80 -610
- package/content/extensions/helpers/kafka/producer.md +134 -5
- package/content/extensions/helpers/kafka/schema-registry.md +45 -70
- package/content/extensions/helpers/logger/hf-logger.md +193 -0
- package/content/extensions/helpers/logger/index.md +64 -563
- package/content/extensions/helpers/logger/pino.md +85 -0
- package/content/extensions/helpers/logger/reference.md +746 -0
- package/content/extensions/helpers/network/api.md +241 -195
- package/content/extensions/helpers/network/index.md +72 -530
- package/content/extensions/helpers/queue/index.md +72 -900
- package/content/extensions/helpers/queue/reference.md +467 -0
- package/content/extensions/helpers/redis/index.md +73 -645
- package/content/extensions/helpers/redis/reference.md +727 -0
- package/content/extensions/helpers/secrets/index.md +66 -0
- package/content/extensions/helpers/socket-io/api.md +305 -203
- package/content/extensions/helpers/socket-io/index.md +66 -432
- package/content/extensions/helpers/storage/api.md +564 -462
- package/content/extensions/helpers/storage/index.md +77 -573
- package/content/extensions/helpers/types/index.md +66 -499
- package/content/extensions/helpers/types/reference.md +650 -0
- package/content/extensions/helpers/uid/index.md +58 -227
- package/content/extensions/helpers/websocket/api.md +329 -216
- package/content/extensions/helpers/websocket/index.md +65 -503
- package/content/extensions/helpers/worker-thread/index.md +58 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
- package/content/guides/core-concepts/persistent/transactions.md +1 -1
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/migrations/redis-helpers-migration.md +1 -1
- package/content/guides/migrations/unified-connectors-migration.md +2 -2
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/references/base/application.md +1 -1
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/datasources-reference.md +599 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +17 -39
- package/content/references/base/filter-system/application-usage.md +69 -121
- package/content/references/base/filter-system/array-operators.md +12 -0
- package/content/references/base/filter-system/comparison-operators.md +12 -0
- package/content/references/base/filter-system/default-filter.md +136 -348
- package/content/references/base/filter-system/fields-order-pagination.md +38 -16
- package/content/references/base/filter-system/index.md +106 -257
- package/content/references/base/filter-system/json-filtering.md +12 -2
- package/content/references/base/filter-system/list-operators.md +16 -2
- package/content/references/base/filter-system/logical-operators.md +13 -0
- package/content/references/base/filter-system/null-operators.md +13 -0
- package/content/references/base/filter-system/pattern-matching.md +12 -0
- package/content/references/base/filter-system/quick-reference.md +11 -2
- package/content/references/base/filter-system/range-operators.md +12 -0
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +156 -233
- package/content/references/base/middlewares.md +35 -21
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +80 -1452
- package/content/references/base/repositories/advanced.md +156 -192
- package/content/references/base/repositories/index.md +77 -650
- package/content/references/base/repositories/mixins.md +22 -18
- package/content/references/base/repositories/relations.md +123 -171
- package/content/references/base/repositories/soft-deletable.md +58 -56
- package/content/references/base/secrets.md +263 -0
- package/content/references/base/services.md +2 -2
- package/content/references/configuration/environment-variables.md +48 -4
- package/content/references/configuration/index.md +49 -31
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/index.md +1 -1
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +29 -62
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +57 -218
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/package.json +8 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# API Reference
|
|
2
2
|
|
|
3
|
-
Automatic interactive API documentation
|
|
3
|
+
Automatic interactive API documentation generated from OpenAPI specs, rendered by a pluggable UI provider - Scalar by default, or classic Swagger UI.
|
|
4
4
|
|
|
5
5
|
> [!NOTE] Renamed from SwaggerComponent
|
|
6
6
|
> Swagger UI is just one of the pluggable UI providers, so the component carries a vendor-neutral name. `SwaggerComponent`, `ISwaggerOptions`, and `SwaggerBindingKeys` remain available as deprecated aliases - existing applications keep working unchanged.
|
|
@@ -14,7 +14,7 @@ Automatic interactive API documentation generation using OpenAPI specifications,
|
|
|
14
14
|
| **UI Factory** | `UIProviderFactory` |
|
|
15
15
|
| **Runtimes** | Both |
|
|
16
16
|
|
|
17
|
-
| Provider | Value | When to
|
|
17
|
+
| Provider | Value | When to use |
|
|
18
18
|
|----------|-------|-------------|
|
|
19
19
|
| **Scalar** | `'scalar'` | Modern, clean UI (default) |
|
|
20
20
|
| **Swagger UI** | `'swagger'` | Classic Swagger interface |
|
|
@@ -25,31 +25,9 @@ import { ApiReferenceComponent, ApiReferenceBindingKeys, UIProviderFactory } fro
|
|
|
25
25
|
import type { IApiReferenceOptions, IUIProvider, IUIConfig, IGetProviderParams } from '@venizia/ignis';
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## In one example
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Skip this step to use the defaults (Scalar UI at `/doc/explorer`). To customize:
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// In your Application class's preConfigure method (src/application.ts)
|
|
36
|
-
import { ApiReferenceBindingKeys, IApiReferenceOptions } from '@venizia/ignis';
|
|
37
|
-
|
|
38
|
-
this.bind<IApiReferenceOptions>({
|
|
39
|
-
key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
|
|
40
|
-
}).toValue({
|
|
41
|
-
restOptions: {
|
|
42
|
-
base: { path: '/doc' },
|
|
43
|
-
doc: { path: '/openapi.json' },
|
|
44
|
-
ui: { path: '/explorer', type: 'swagger' }, // Use Swagger UI instead of Scalar
|
|
45
|
-
},
|
|
46
|
-
explorer: {
|
|
47
|
-
openapi: '3.0.0',
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Step 2: Register Component
|
|
30
|
+
Register the component - the docs UI comes up at `/doc/explorer`, the raw spec at `/doc/openapi.json`. No configuration required.
|
|
53
31
|
|
|
54
32
|
```typescript
|
|
55
33
|
// src/application.ts
|
|
@@ -57,15 +35,12 @@ import { ApiReferenceComponent, BaseApplication, ValueOrPromise } from '@venizia
|
|
|
57
35
|
|
|
58
36
|
export class Application extends BaseApplication {
|
|
59
37
|
preConfigure(): ValueOrPromise<void> {
|
|
60
|
-
// ...
|
|
61
38
|
this.component(ApiReferenceComponent);
|
|
62
39
|
}
|
|
63
40
|
}
|
|
64
41
|
```
|
|
65
42
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
To get the most out of the documentation, define your routes with `zod` schemas:
|
|
43
|
+
Define routes with Zod schemas so they show up in the generated spec:
|
|
69
44
|
|
|
70
45
|
```typescript
|
|
71
46
|
// src/controllers/hello.controller.ts
|
|
@@ -100,45 +75,64 @@ export class HelloController extends BaseRestController {
|
|
|
100
75
|
```
|
|
101
76
|
|
|
102
77
|
> [!TIP]
|
|
103
|
-
>
|
|
78
|
+
> Only routes registered through `defineRoute`, `bindRoute`, or `@api()` with `@hono/zod-openapi` schemas appear in the generated spec.
|
|
104
79
|
|
|
105
|
-
##
|
|
80
|
+
## How it works
|
|
106
81
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
| `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed to the UI provider |
|
|
82
|
+
- **Options merge group by group.** `binding()` reads the bound `IApiReferenceOptions`, then shallow-merges `base`, `doc`, and `ui` each against their own defaults - overriding `ui.type` alone still keeps `ui.path` and every `base`/`doc` field.
|
|
83
|
+
- **`explorer.info` is always overwritten.** The component unconditionally reads your `package.json` (via `application.getAppInfo()`) and replaces `explorer.info` with `{ title, version, description, contact }` - any `explorer.info` you bind is discarded. Edit `package.json` instead.
|
|
84
|
+
- **`explorer.servers` fills in only when empty.** A supplied server entry is kept as-is; otherwise the component builds one from `application.getServerAddress()` plus the base path.
|
|
85
|
+
- **UI type resolution uses `??`, not `||`.** The source is `restOptions.ui.type ?? DocumentUITypes.SWAGGER` - only `null`/`undefined` falls back, and it falls back to `'swagger'`, not the configured default `'scalar'`. An explicit empty string is NOT repaired by this fallback - it fails `DocumentUITypes.isValid()` and the component throws `Invalid document UI Type` immediately.
|
|
86
|
+
- **UI libraries load lazily.** `SwaggerUIProvider`/`ScalarUIProvider` each `await import()` their rendering library inside `render()`, on the first request to the docs UI - not at application startup. Only the configured provider's library is ever loaded.
|
|
87
|
+
- **`ScalarUIProvider` renames `title` to `pageTitle`.** A quirk to know if you inspect the rendered output or write a custom UI provider: Scalar's own API takes `pageTitle`, not `title`.
|
|
88
|
+
- **Security schemes are always registered.** JWT (`bearer`) and Basic security schemes are added to the OpenAPI registry unconditionally, so routes using `authenticate: { strategies: ['jwt'] }` or `['basic']` render the correct auth UI.
|
|
115
89
|
|
|
116
|
-
|
|
117
|
-
> 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.
|
|
90
|
+
## Common tasks
|
|
118
91
|
|
|
119
|
-
|
|
120
|
-
|
|
92
|
+
### Switch to Swagger UI
|
|
93
|
+
```typescript
|
|
94
|
+
this.bind<IApiReferenceOptions>({
|
|
95
|
+
key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
|
|
96
|
+
}).toValue({ restOptions: { ui: { type: 'swagger' } } });
|
|
97
|
+
```
|
|
121
98
|
|
|
122
|
-
|
|
99
|
+
### Move the docs under a different base path
|
|
100
|
+
```typescript
|
|
101
|
+
this.bind<IApiReferenceOptions>({
|
|
102
|
+
key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
|
|
103
|
+
}).toValue({ restOptions: { base: { path: '/api-docs' } } });
|
|
104
|
+
```
|
|
105
|
+
Result: UI at `/api-docs/explorer`, spec at `/api-docs/openapi.json` - the group merge keeps `doc.path`/`ui.path` defaults.
|
|
106
|
+
|
|
107
|
+
### Set the info block shown in the UI
|
|
108
|
+
`explorer.info` always comes from `package.json` - update `name`, `version`, `description`, and `author` there; binding `explorer.info` directly has no effect.
|
|
109
|
+
|
|
110
|
+
### Register a custom UI provider
|
|
111
|
+
`UIProviderFactory.register()` only understands `'swagger'`/`'scalar'`. Register a custom provider directly on the factory before `ApiReferenceComponent.binding()` runs:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
UIProviderFactory.getInstance().set('my-ui', new MyCustomUIProvider());
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Reference
|
|
118
|
+
|
|
119
|
+
### Options
|
|
123
120
|
```typescript
|
|
124
121
|
export interface IApiReferenceOptions {
|
|
125
|
-
restOptions
|
|
126
|
-
base
|
|
127
|
-
doc
|
|
128
|
-
ui
|
|
122
|
+
restOptions?: {
|
|
123
|
+
base?: { path?: string };
|
|
124
|
+
doc?: { path?: string };
|
|
125
|
+
ui?: { path?: string; type?: TDocumentUIType };
|
|
129
126
|
};
|
|
130
|
-
explorer
|
|
131
|
-
openapi
|
|
127
|
+
explorer?: {
|
|
128
|
+
openapi?: string;
|
|
132
129
|
info?: {
|
|
133
130
|
title: string;
|
|
134
131
|
version: string;
|
|
135
132
|
description: string;
|
|
136
133
|
contact?: { name: string; email: string };
|
|
137
134
|
};
|
|
138
|
-
servers?: Array<{
|
|
139
|
-
url: string;
|
|
140
|
-
description?: string;
|
|
141
|
-
}>;
|
|
135
|
+
servers?: Array<{ url: string; description?: string }>;
|
|
142
136
|
};
|
|
143
137
|
uiConfig?: Record<string, any>;
|
|
144
138
|
}
|
|
@@ -151,194 +145,18 @@ export interface IApiReferenceOptions {
|
|
|
151
145
|
| `restOptions.ui.path` | `string` | `'/explorer'` | Path to the documentation UI (relative to base) |
|
|
152
146
|
| `restOptions.ui.type` | `'swagger' \| 'scalar'` | `'scalar'` | UI provider type |
|
|
153
147
|
| `explorer.openapi` | `string` | `'3.0.0'` | OpenAPI specification version |
|
|
154
|
-
| `explorer.info.title`
|
|
155
|
-
| `explorer.info.version` | `string` | Always from `package.json` `version` | API version (overwritten at runtime) |
|
|
156
|
-
| `explorer.info.description` | `string` | Always from `package.json` `description` | API description (overwritten at runtime) |
|
|
157
|
-
| `explorer.info.contact` | `{ name, email }` | Always from `package.json` `author` | Contact information (overwritten at runtime) |
|
|
148
|
+
| `explorer.info.title` / `.version` / `.description` / `.contact` | - | Always sourced from `package.json` | Overwritten at runtime - binding values are discarded |
|
|
158
149
|
| `explorer.servers` | `Array<{ url, description? }>` | Auto-detected when empty | Server URLs |
|
|
159
|
-
| `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed to the UI provider |
|
|
160
|
-
|
|
161
|
-
#### IGetProviderParams Interface
|
|
162
|
-
|
|
163
|
-
The `IGetProviderParams` interface is used by `UIProviderFactory.getProvider()` and `UIProviderFactory.register()`:
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
export interface IGetProviderParams {
|
|
167
|
-
type: string;
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
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.
|
|
172
|
-
|
|
173
|
-
### Tech Stack
|
|
174
|
-
|
|
175
|
-
| Library | Purpose |
|
|
176
|
-
|---------|---------|
|
|
177
|
-
| `@hono/zod-openapi` | OpenAPI generation from Zod schemas |
|
|
178
|
-
| `@hono/swagger-ui` | Swagger UI rendering |
|
|
179
|
-
| `@scalar/hono-api-reference` | Scalar UI rendering |
|
|
180
|
-
| `zod` | Schema validation and type generation |
|
|
181
|
-
|
|
182
|
-
> [!TIP]
|
|
183
|
-
> 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.
|
|
184
|
-
|
|
185
|
-
## Architecture
|
|
186
|
-
|
|
187
|
-
### Component Lifecycle
|
|
188
|
-
|
|
189
|
-
The `ApiReferenceComponent` executes the following during `binding()`:
|
|
190
|
-
|
|
191
|
-
1. **Resolve options** -- reads `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` from DI using `application.get()` with `isOptional: true`, then deep-merges what it finds over `DEFAULT_API_REFERENCE_OPTIONS` group by group, so an application that overrides one path keeps the defaults for the rest
|
|
192
|
-
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 }`
|
|
193
|
-
3. **Auto-detect servers** -- if `explorer.servers` is empty or unset, creates one entry from `http://` + `application.getServerAddress()` + `configs.path.base`
|
|
194
|
-
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
|
|
195
|
-
5. **Register OpenAPI doc route** -- calls `rootRouter.doc(docPath, explorer)` to register the raw JSON endpoint
|
|
196
|
-
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'`
|
|
197
|
-
7. **Validate UI type** -- checks the resolved type against `DocumentUITypes.SCHEME_SET`, throws if invalid
|
|
198
|
-
8. **Register UI provider** -- calls `UIProviderFactory.register({ type })` to instantiate the UI renderer
|
|
199
|
-
9. **Construct docUrl** -- builds the full documentation URL by joining `configs.path.base`, `configs.basePath`, and the computed `docPath`
|
|
200
|
-
10. **Register UI route** -- creates `GET` handler at `uiPath` that calls `uiProvider.render()` with `{ title: appInfo.name, url: docUrl, ...uiConfig }`
|
|
201
|
-
11. **Register security schemes** -- auto-registers JWT (bearer) and Basic security schemes in the OpenAPI registry
|
|
202
|
-
|
|
203
|
-
### Architecture Components
|
|
204
|
-
|
|
205
|
-
| Component | Class | Role |
|
|
206
|
-
|-----------|-------|------|
|
|
207
|
-
| **ApiReferenceComponent** | `extends BaseComponent` | Orchestrates binding, overwrites OpenAPI metadata from `package.json` |
|
|
208
|
-
| **UIProviderFactory** | `extends MemoryStorageHelper` (singleton) | Registry for UI providers, validates and instantiates |
|
|
209
|
-
| **SwaggerUIProvider** | `implements IUIProvider` | Renders Swagger UI via `@hono/swagger-ui` |
|
|
210
|
-
| **ScalarUIProvider** | `implements IUIProvider` | Renders Scalar UI via `@scalar/hono-api-reference` |
|
|
211
|
-
|
|
212
|
-
#### UIProviderFactory and MemoryStorageHelper
|
|
213
|
-
|
|
214
|
-
`UIProviderFactory` extends `MemoryStorageHelper<{ [key: string | symbol]: IUIProvider }>`, which provides a simple in-memory key-value store with the following methods used internally:
|
|
215
|
-
|
|
216
|
-
- `isBound(key)` -- checks if a provider type is already registered
|
|
217
|
-
- `get(key)` -- retrieves a registered provider instance
|
|
218
|
-
- `set(key, value)` -- stores a provider instance
|
|
219
|
-
- `keys()` -- lists all registered provider type keys
|
|
220
|
-
|
|
221
|
-
This gives the factory a lightweight, type-safe storage backend without requiring the full DI container.
|
|
222
|
-
|
|
223
|
-
#### Lazy Dynamic Imports
|
|
224
|
-
|
|
225
|
-
Both `SwaggerUIProvider` and `ScalarUIProvider` use `await import()` inside their `render()` method to load the underlying UI library:
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
// SwaggerUIProvider
|
|
229
|
-
async render(context, config, next) {
|
|
230
|
-
const { swaggerUI } = await import('@hono/swagger-ui');
|
|
231
|
-
// ...
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// ScalarUIProvider
|
|
235
|
-
async render(context, config, next) {
|
|
236
|
-
const { Scalar } = await import('@scalar/hono-api-reference');
|
|
237
|
-
// ...
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
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).
|
|
242
|
-
|
|
243
|
-
#### ScalarUIProvider Title Mapping
|
|
244
|
-
|
|
245
|
-
The `ScalarUIProvider` maps the `title` field to `pageTitle` when calling the Scalar renderer:
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
const { title, url, ...customConfig } = config;
|
|
249
|
-
return Scalar({ url, pageTitle: title, ...customConfig })(context, next);
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
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`.
|
|
253
|
-
|
|
254
|
-
### UIProviderFactory API
|
|
255
|
-
|
|
256
|
-
| Method | Signature | Description |
|
|
257
|
-
|--------|-----------|-------------|
|
|
258
|
-
| `getInstance()` | `static () => UIProviderFactory` | Returns singleton instance |
|
|
259
|
-
| `register()` | `(opts: { type: string }) => void` | Instantiates and registers a UI provider (idempotent) |
|
|
260
|
-
| `getProvider()` | `(opts: IGetProviderParams) => IUIProvider` | Returns registered provider or throws |
|
|
261
|
-
| `getRegisteredProviders()` | `() => string[]` | Lists all registered provider type keys |
|
|
262
|
-
|
|
263
|
-
#### register() Idempotency
|
|
264
|
-
|
|
265
|
-
The `register()` method is idempotent. If a provider of the given type is already registered, it logs a warning and returns without error:
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
register(opts: { type: string }): void {
|
|
269
|
-
if (this.isBound(opts.type)) {
|
|
270
|
-
this.logger
|
|
271
|
-
.for(this.register.name)
|
|
272
|
-
.warn('Skip registering BOUNDED Document UI | type: %s', opts.type);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
// ... instantiate and store the provider
|
|
276
|
-
}
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
This means calling `register({ type: 'scalar' })` multiple times is safe and will not create duplicate provider instances.
|
|
280
|
-
|
|
281
|
-
### IUIProvider Interface
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
interface IUIProvider {
|
|
285
|
-
render(context: Context, config: IUIConfig, next: Next): Promise<Response | void>;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
interface IUIConfig {
|
|
289
|
-
title: string; // App name from package.json
|
|
290
|
-
url: string; // Full URL to OpenAPI JSON endpoint
|
|
291
|
-
[key: string]: any; // Additional config from uiConfig option
|
|
292
|
-
}
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Security Scheme Registration
|
|
296
|
-
|
|
297
|
-
The component auto-registers two OpenAPI security schemes:
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
// JWT Bearer
|
|
301
|
-
rootRouter.openAPIRegistry.registerComponent('securitySchemes', 'jwt', {
|
|
302
|
-
type: 'http',
|
|
303
|
-
scheme: 'bearer',
|
|
304
|
-
bearerFormat: 'JWT',
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// Basic Auth
|
|
308
|
-
rootRouter.openAPIRegistry.registerComponent('securitySchemes', 'basic', {
|
|
309
|
-
type: 'http',
|
|
310
|
-
scheme: 'basic',
|
|
311
|
-
});
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
This ensures routes using `authStrategies: ['jwt']` or `authStrategies: ['basic']` display the correct auth UI (lock icon + input fields) in the documentation.
|
|
315
|
-
|
|
316
|
-
## Binding Keys
|
|
150
|
+
| `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed through to the UI provider |
|
|
317
151
|
|
|
152
|
+
### Binding keys
|
|
318
153
|
| Key | Constant | Type | Required | Default |
|
|
319
154
|
|-----|----------|------|----------|---------|
|
|
320
|
-
| `@app/api-reference/options` | `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` | `IApiReferenceOptions` | No | See
|
|
321
|
-
|
|
322
|
-
The deprecated `SwaggerBindingKeys.SWAGGER_OPTIONS` still resolves - it is an alias whose **value** is that same `'@app/api-reference/options'` string. There is no binding under the literal `'@app/swagger/options'`; binding that raw string does nothing.
|
|
155
|
+
| `@app/api-reference/options` | `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` | `IApiReferenceOptions` | No | See Options table |
|
|
323
156
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
super({
|
|
328
|
-
scope: ApiReferenceComponent.name,
|
|
329
|
-
initDefault: { enable: true, container: application },
|
|
330
|
-
bindings: {
|
|
331
|
-
[ApiReferenceBindingKeys.API_REFERENCE_OPTIONS]: Binding.bind<IApiReferenceOptions>({
|
|
332
|
-
key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
|
|
333
|
-
}).toValue(DEFAULT_API_REFERENCE_OPTIONS),
|
|
334
|
-
},
|
|
335
|
-
});
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
`binding()` then reads the key back with `isOptional: true` and **deep-merges** whatever the application bound over the defaults, group by group (`base`, `doc`, `ui`, `explorer`) - so overriding one path does not wipe the others. The merge builds a fresh `explorer` object per application; mutating the bound one would leak this application's info into every later application in the same process.
|
|
157
|
+
`SwaggerBindingKeys.SWAGGER_OPTIONS` is a deprecated alias whose VALUE is the same `'@app/api-reference/options'` string - there is no separate binding under the literal `'@app/swagger/options'`.
|
|
339
158
|
|
|
340
159
|
**Default value:**
|
|
341
|
-
|
|
342
160
|
```typescript
|
|
343
161
|
const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
|
|
344
162
|
restOptions: {
|
|
@@ -358,10 +176,27 @@ const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
|
|
|
358
176
|
```
|
|
359
177
|
|
|
360
178
|
> [!NOTE]
|
|
361
|
-
> The `explorer.info` values
|
|
179
|
+
> The `explorer.info` values above are never used at runtime - `binding()` unconditionally overwrites `explorer.info` from `package.json`. They exist only as structural defaults.
|
|
362
180
|
|
|
363
|
-
###
|
|
181
|
+
### API endpoints
|
|
182
|
+
| Method | Path (default) | Description |
|
|
183
|
+
|--------|-----------------|-------------|
|
|
184
|
+
| `GET` | `/doc/explorer` | Documentation UI (Scalar by default) |
|
|
185
|
+
| `GET` | `/doc/openapi.json` | Raw OpenAPI specification |
|
|
364
186
|
|
|
187
|
+
Actual paths shift with `restOptions.base.path`, `restOptions.ui.path`, and `restOptions.doc.path`.
|
|
188
|
+
|
|
189
|
+
### UIProviderFactory
|
|
190
|
+
| Method | Signature | Description |
|
|
191
|
+
|--------|-----------|-------------|
|
|
192
|
+
| `getInstance()` | `static () => UIProviderFactory` | Returns the singleton instance |
|
|
193
|
+
| `register()` | `(opts: { type: string }) => void` | Instantiates and registers a built-in provider; idempotent - warns and returns if the type is already bound |
|
|
194
|
+
| `getProvider()` | `(opts: IGetProviderParams) => IUIProvider` | Returns the registered provider or throws `Unknown UI Provider` |
|
|
195
|
+
| `getRegisteredProviders()` | `() => string[]` | Lists all registered provider type keys |
|
|
196
|
+
|
|
197
|
+
Extends `MemoryStorageHelper<{ [key: string | symbol]: IUIProvider }>`, using `isBound()` / `get()` / `set()` / `keys()` for lightweight, type-safe storage without the full DI container.
|
|
198
|
+
|
|
199
|
+
### Type definitions
|
|
365
200
|
```typescript
|
|
366
201
|
type TDocumentUIType = TConstValue<typeof DocumentUITypes>;
|
|
367
202
|
|
|
@@ -373,96 +208,38 @@ class DocumentUITypes {
|
|
|
373
208
|
}
|
|
374
209
|
```
|
|
375
210
|
|
|
376
|
-
`TDocumentUIType` is derived via `TConstValue`, which extracts the union of
|
|
211
|
+
`TDocumentUIType` is derived via `TConstValue`, which extracts the union of every `static readonly` string on `DocumentUITypes` - the type stays in sync with the constants automatically.
|
|
377
212
|
|
|
378
|
-
|
|
213
|
+
### Component lifecycle (`binding()`)
|
|
214
|
+
1. **Resolve options** - reads `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` with `isOptional: true`, then merges `base`/`doc`/`ui` each against `DEFAULT_API_REFERENCE_OPTIONS`
|
|
215
|
+
2. **Overwrite info** - reads `package.json` via `application.getAppInfo()` and replaces `explorer.info`
|
|
216
|
+
3. **Auto-detect servers** - builds one entry from `application.getServerAddress()` when `explorer.servers` is empty
|
|
217
|
+
4. **Normalize paths** - ensures every path segment (`base.path`, `doc.path`, `ui.path`) has a leading `/`
|
|
218
|
+
5. **Register the OpenAPI doc route** - `rootRouter.doc(docPath, explorer)`
|
|
219
|
+
6. **Resolve `uiType`** - `restOptions.ui.type ?? DocumentUITypes.SWAGGER`
|
|
220
|
+
7. **Validate and register the UI provider** - via `UIProviderFactory`, unless a provider with that type is already bound
|
|
221
|
+
8. **Register the UI route** - `GET` handler at `uiPath` calling `uiProvider.render()`
|
|
222
|
+
9. **Register JWT and Basic security schemes** on the OpenAPI registry
|
|
379
223
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
### Documentation UI Endpoint
|
|
389
|
-
|
|
390
|
-
**Default path:** `/doc/explorer`
|
|
391
|
-
|
|
392
|
-
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.
|
|
393
|
-
|
|
394
|
-
### OpenAPI JSON Endpoint
|
|
395
|
-
|
|
396
|
-
**Default path:** `/doc/openapi.json`
|
|
397
|
-
|
|
398
|
-
Returns the raw OpenAPI JSON specification generated from all registered controller routes and their Zod schemas. This endpoint can be used by:
|
|
399
|
-
- External API testing tools (Postman, Insomnia)
|
|
400
|
-
- CI pipelines for API contract validation
|
|
401
|
-
- Client SDK generators (openapi-generator, orval)
|
|
402
|
-
- API gateway configuration
|
|
224
|
+
### Tech stack
|
|
225
|
+
| Library | Purpose |
|
|
226
|
+
|---------|---------|
|
|
227
|
+
| `@hono/zod-openapi` | OpenAPI generation from Zod schemas |
|
|
228
|
+
| `@hono/swagger-ui` | Swagger UI rendering |
|
|
229
|
+
| `@scalar/hono-api-reference` | Scalar UI rendering |
|
|
230
|
+
| `zod` | Schema validation and type generation |
|
|
403
231
|
|
|
404
232
|
## Troubleshooting
|
|
405
233
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
this.bind<IApiReferenceOptions>({
|
|
414
|
-
key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
|
|
415
|
-
}).toValue({
|
|
416
|
-
restOptions: {
|
|
417
|
-
base: { path: '/doc' },
|
|
418
|
-
doc: { path: '/openapi.json' },
|
|
419
|
-
ui: { path: '/explorer', type: 'scalar' }, // 'scalar' or 'swagger'
|
|
420
|
-
},
|
|
421
|
-
explorer: { openapi: '3.0.0' },
|
|
422
|
-
});
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### Documentation UI shows no routes
|
|
426
|
-
|
|
427
|
-
**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.
|
|
428
|
-
|
|
429
|
-
**Fix:** Use `defineRoute` with Zod response schemas in your controllers:
|
|
430
|
-
|
|
431
|
-
```typescript
|
|
432
|
-
this.defineRoute({
|
|
433
|
-
configs: {
|
|
434
|
-
path: '/',
|
|
435
|
-
method: 'get',
|
|
436
|
-
responses: {
|
|
437
|
-
200: jsonContent({
|
|
438
|
-
description: 'Success',
|
|
439
|
-
schema: z.object({ message: z.string() }),
|
|
440
|
-
}),
|
|
441
|
-
},
|
|
442
|
-
},
|
|
443
|
-
handler: (c) => c.json({ message: 'ok' }, 200),
|
|
444
|
-
});
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
### "Unknown UI Provider"
|
|
234
|
+
| Symptom | Cause | Fix |
|
|
235
|
+
|---------|-------|-----|
|
|
236
|
+
| `Invalid document UI Type` | `restOptions.ui.type` is not `'swagger'` or `'scalar'` - an explicit empty string is NOT repaired by the `??` fallback | Use `'scalar'` or `'swagger'` explicitly |
|
|
237
|
+
| Documentation UI shows no routes | Controllers aren't defining routes with Zod schemas via `defineRoute`, `bindRoute`, or `@api()` | Add Zod response schemas to your route configs |
|
|
238
|
+
| `Unknown UI Provider` | `UIProviderFactory.getProvider()` was called with a type that was never registered - usually a failed `binding()` | Ensure `ApiReferenceComponent` is registered in `preConfigure()`; check logs for warnings during binding |
|
|
239
|
+
| OpenAPI spec missing authentication schemes | `AuthenticationComponent` isn't registered, so auth strategies aren't available when schemes are added | Register `AuthenticationComponent` before `ApiReferenceComponent` in `preConfigure()` |
|
|
240
|
+
| `explorer.info` doesn't match my binding | `explorer.info` is always overwritten from `package.json` during `binding()` | Update `package.json` fields (`name`, `version`, `description`, `author`) instead |
|
|
448
241
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
**Fix:** Ensure the `ApiReferenceComponent` is registered in `preConfigure()` and that no errors occur during its `binding()` phase. Check the application logs for warnings from `UIProviderFactory`.
|
|
452
|
-
|
|
453
|
-
### OpenAPI spec missing authentication schemes
|
|
454
|
-
|
|
455
|
-
**Cause:** The `ApiReferenceComponent` auto-registers JWT and Basic security schemes. If the `AuthenticationComponent` is not registered, authenticated routes will not show auth UI in the documentation.
|
|
456
|
-
|
|
457
|
-
**Fix:** Register `AuthenticationComponent` before `ApiReferenceComponent` in `preConfigure()` to ensure auth strategies are available when the Swagger component configures security schemes.
|
|
458
|
-
|
|
459
|
-
### explorer.info values not matching custom configuration
|
|
460
|
-
|
|
461
|
-
**Cause:** The `ApiReferenceComponent` 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.
|
|
462
|
-
|
|
463
|
-
**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()`.
|
|
464
|
-
|
|
465
|
-
## See Also
|
|
242
|
+
## See also
|
|
466
243
|
|
|
467
244
|
- **Guides:**
|
|
468
245
|
- [Components Overview](/guides/core-concepts/components) - Component system basics
|
|
@@ -480,3 +257,11 @@ this.defineRoute({
|
|
|
480
257
|
- [OpenAPI Specification](https://swagger.io/specification/) - OpenAPI standard
|
|
481
258
|
- [Scalar Documentation](https://github.com/scalar/scalar) - Scalar API documentation UI
|
|
482
259
|
- [@hono/zod-openapi](https://github.com/honojs/middleware/tree/main/packages/zod-openapi) - Hono OpenAPI integration
|
|
260
|
+
|
|
261
|
+
**Files:**
|
|
262
|
+
|
|
263
|
+
- [`packages/core/src/components/api-reference/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/component.ts) - `ApiReferenceComponent`
|
|
264
|
+
- [`packages/core/src/components/api-reference/ui-factory.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/ui-factory.ts) - `UIProviderFactory`, `SwaggerUIProvider`, `ScalarUIProvider`
|
|
265
|
+
- [`packages/core/src/components/api-reference/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/common/types.ts) - `IApiReferenceOptions`, `IUIProvider`, `IUIConfig`
|
|
266
|
+
- [`packages/core/src/components/api-reference/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/common/keys.ts) - `ApiReferenceBindingKeys`
|
|
267
|
+
- [`packages/core/src/components/api-reference/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/common/constants.ts) - `DocumentUITypes`
|