@venizia/ignis-docs 0.0.7 → 0.0.8-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/dist/mcp-server/common/paths.d.ts +4 -2
- package/dist/mcp-server/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +8 -6
- package/dist/mcp-server/common/paths.js.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.js +7 -7
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +3 -3
- package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
- package/package.json +1 -1
- package/wiki/best-practices/api-usage-examples.md +9 -9
- package/wiki/best-practices/architectural-patterns.md +19 -3
- package/wiki/best-practices/architecture-decisions.md +6 -6
- package/wiki/best-practices/code-style-standards/advanced-patterns.md +1 -1
- package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
- package/wiki/best-practices/code-style-standards/function-patterns.md +2 -2
- package/wiki/best-practices/code-style-standards/index.md +2 -2
- package/wiki/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/wiki/best-practices/code-style-standards/route-definitions.md +4 -4
- package/wiki/best-practices/data-modeling.md +1 -1
- package/wiki/best-practices/deployment-strategies.md +1 -1
- package/wiki/best-practices/error-handling.md +2 -2
- 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/{references → extensions}/components/authentication/api.md +12 -20
- package/wiki/{references → extensions}/components/authentication/errors.md +1 -1
- package/wiki/{references → extensions}/components/authentication/index.md +5 -8
- package/wiki/{references → extensions}/components/authentication/usage.md +20 -36
- package/wiki/{references → extensions}/components/authorization/api.md +62 -13
- package/wiki/{references → extensions}/components/authorization/errors.md +12 -7
- package/wiki/{references → extensions}/components/authorization/index.md +93 -6
- package/wiki/{references → extensions}/components/authorization/usage.md +42 -4
- package/wiki/{references → extensions}/components/health-check.md +5 -4
- package/wiki/{references → extensions}/components/index.md +2 -0
- package/wiki/{references → extensions}/components/mail/index.md +1 -1
- package/wiki/{references → extensions}/components/request-tracker.md +1 -1
- package/wiki/{references → extensions}/components/socket-io/api.md +2 -2
- package/wiki/{references → extensions}/components/socket-io/errors.md +2 -0
- package/wiki/{references → extensions}/components/socket-io/index.md +24 -20
- package/wiki/{references → extensions}/components/socket-io/usage.md +2 -2
- package/wiki/{references → extensions}/components/static-asset/api.md +14 -15
- package/wiki/{references → extensions}/components/static-asset/errors.md +3 -1
- package/wiki/{references → extensions}/components/static-asset/index.md +158 -89
- package/wiki/{references → extensions}/components/static-asset/usage.md +8 -5
- package/wiki/{references → extensions}/components/swagger.md +3 -3
- package/wiki/{references → extensions}/components/template/index.md +4 -4
- package/wiki/{references → extensions}/components/template/setup-page.md +1 -1
- package/wiki/{references → extensions}/components/template/single-page.md +1 -1
- package/wiki/{references → extensions}/components/websocket/api.md +7 -6
- package/wiki/{references → extensions}/components/websocket/errors.md +17 -3
- package/wiki/{references → extensions}/components/websocket/index.md +17 -11
- package/wiki/{references → extensions}/components/websocket/usage.md +2 -2
- package/wiki/{references → extensions}/helpers/crypto/index.md +1 -1
- package/wiki/{references → extensions}/helpers/env/index.md +9 -5
- package/wiki/{references → extensions}/helpers/error/index.md +2 -7
- package/wiki/{references → extensions}/helpers/index.md +18 -6
- package/wiki/{references → extensions}/helpers/kafka/admin.md +13 -1
- package/wiki/{references → extensions}/helpers/kafka/consumer.md +28 -28
- package/wiki/{references → extensions}/helpers/kafka/examples.md +19 -19
- package/wiki/{references → extensions}/helpers/kafka/index.md +51 -48
- package/wiki/{references → extensions}/helpers/kafka/producer.md +18 -18
- package/wiki/{references → extensions}/helpers/kafka/schema-registry.md +25 -25
- package/wiki/{references → extensions}/helpers/logger/index.md +2 -2
- package/wiki/{references → extensions}/helpers/queue/index.md +400 -4
- package/wiki/{references → extensions}/helpers/storage/api.md +170 -10
- package/wiki/{references → extensions}/helpers/storage/index.md +44 -8
- package/wiki/{references → extensions}/helpers/template/index.md +1 -1
- package/wiki/{references → extensions}/helpers/testing/index.md +4 -4
- package/wiki/{references → extensions}/helpers/types/index.md +63 -16
- package/wiki/{references → extensions}/helpers/websocket/index.md +1 -1
- package/wiki/extensions/index.md +48 -0
- package/wiki/guides/core-concepts/application/bootstrapping.md +55 -37
- package/wiki/guides/core-concepts/application/index.md +95 -35
- package/wiki/guides/core-concepts/components-guide.md +23 -19
- package/wiki/guides/core-concepts/components.md +34 -10
- package/wiki/guides/core-concepts/dependency-injection.md +99 -34
- package/wiki/guides/core-concepts/grpc-controllers.md +295 -0
- package/wiki/guides/core-concepts/persistent/datasources.md +27 -8
- package/wiki/guides/core-concepts/persistent/models.md +43 -1
- package/wiki/guides/core-concepts/persistent/repositories.md +75 -8
- package/wiki/guides/core-concepts/persistent/transactions.md +38 -8
- package/wiki/guides/core-concepts/{controllers.md → rest-controllers.md} +30 -33
- package/wiki/guides/core-concepts/services.md +19 -5
- package/wiki/guides/get-started/5-minute-quickstart.md +6 -7
- package/wiki/guides/get-started/philosophy.md +1 -1
- package/wiki/guides/index.md +2 -2
- package/wiki/guides/reference/glossary.md +7 -7
- package/wiki/guides/reference/mcp-docs-server.md +1 -1
- package/wiki/guides/tutorials/building-a-crud-api.md +2 -2
- package/wiki/guides/tutorials/complete-installation.md +17 -14
- package/wiki/guides/tutorials/ecommerce-api.md +18 -18
- package/wiki/guides/tutorials/realtime-chat.md +8 -8
- package/wiki/guides/tutorials/testing.md +2 -2
- package/wiki/index.md +4 -3
- package/wiki/references/base/application.md +341 -21
- package/wiki/references/base/bootstrapping.md +43 -13
- package/wiki/references/base/components.md +259 -8
- package/wiki/references/base/controllers.md +556 -253
- package/wiki/references/base/datasources.md +159 -79
- package/wiki/references/base/dependency-injection.md +299 -48
- package/wiki/references/base/filter-system/application-usage.md +18 -2
- package/wiki/references/base/filter-system/array-operators.md +14 -6
- package/wiki/references/base/filter-system/comparison-operators.md +9 -3
- package/wiki/references/base/filter-system/default-filter.md +28 -3
- package/wiki/references/base/filter-system/fields-order-pagination.md +17 -13
- package/wiki/references/base/filter-system/index.md +169 -11
- package/wiki/references/base/filter-system/json-filtering.md +51 -18
- package/wiki/references/base/filter-system/list-operators.md +4 -3
- package/wiki/references/base/filter-system/logical-operators.md +7 -2
- package/wiki/references/base/filter-system/null-operators.md +50 -0
- package/wiki/references/base/filter-system/quick-reference.md +82 -243
- package/wiki/references/base/filter-system/range-operators.md +7 -1
- package/wiki/references/base/filter-system/tips.md +34 -7
- package/wiki/references/base/filter-system/use-cases.md +6 -5
- package/wiki/references/base/grpc-controllers.md +984 -0
- package/wiki/references/base/index.md +32 -24
- package/wiki/references/base/middleware.md +347 -0
- package/wiki/references/base/models.md +390 -46
- package/wiki/references/base/providers.md +14 -14
- package/wiki/references/base/repositories/advanced.md +84 -69
- package/wiki/references/base/repositories/index.md +447 -12
- package/wiki/references/base/repositories/mixins.md +103 -98
- package/wiki/references/base/repositories/relations.md +129 -45
- package/wiki/references/base/repositories/soft-deletable.md +104 -23
- package/wiki/references/base/services.md +94 -14
- package/wiki/references/index.md +12 -10
- package/wiki/references/quick-reference.md +98 -65
- package/wiki/references/utilities/crypto.md +21 -4
- package/wiki/references/utilities/date.md +25 -7
- package/wiki/references/utilities/index.md +26 -24
- package/wiki/references/utilities/jsx.md +54 -54
- package/wiki/references/utilities/module.md +8 -6
- package/wiki/references/utilities/parse.md +16 -9
- package/wiki/references/utilities/performance.md +22 -7
- package/wiki/references/utilities/promise.md +19 -16
- package/wiki/references/utilities/request.md +48 -26
- package/wiki/references/utilities/schema.md +69 -6
- package/wiki/references/utilities/statuses.md +131 -140
- /package/wiki/{references → extensions}/components/mail/api.md +0 -0
- /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
- /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
- /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
- /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
- /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
- /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
- /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
- /package/wiki/{references → extensions}/src-details/mcp-server.md +0 -0
|
@@ -71,13 +71,26 @@ export class UserRepository extends ReadableRepository<typeof User.schema> {
|
|
|
71
71
|
> - After the first argument, you can inject any additional dependencies you need
|
|
72
72
|
> - When `@inject` is at param index 0, auto-injection is skipped
|
|
73
73
|
|
|
74
|
-
## Repository
|
|
74
|
+
## Repository Hierarchy
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
AbstractRepository (base + mixins: FieldsVisibilityMixin + DefaultFilterMixin)
|
|
78
|
+
↓
|
|
79
|
+
ReadableRepository (read-only: find, findOne, findById, count, existsWith)
|
|
80
|
+
↓
|
|
81
|
+
PersistableRepository (+ create, updateById, updateAll)
|
|
82
|
+
↓
|
|
83
|
+
DefaultCRUDRepository (+ deleteById, deleteAll) — recommended default
|
|
84
|
+
↓
|
|
85
|
+
SoftDeletableRepository (overrides delete to set deletedAt timestamp)
|
|
86
|
+
```
|
|
75
87
|
|
|
76
88
|
| Type | Description |
|
|
77
89
|
|------|-------------|
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
90
|
+
| `ReadableRepository` | Read-only operations. Write operations throw errors. |
|
|
91
|
+
| `PersistableRepository` | Read + write operations (create, update). Extends ReadableRepository. |
|
|
92
|
+
| `DefaultCRUDRepository` | Full CRUD including delete. Extends PersistableRepository. **Recommended for most use cases.** |
|
|
93
|
+
| `SoftDeletableRepository` | Extends DefaultCRUDRepository. Overrides delete to set `deletedAt` timestamp instead of physically removing records. |
|
|
81
94
|
|
|
82
95
|
## Querying Data
|
|
83
96
|
|
|
@@ -134,6 +147,32 @@ await repo.updateById({
|
|
|
134
147
|
await repo.deleteById({ id: 'uuid-here' });
|
|
135
148
|
```
|
|
136
149
|
|
|
150
|
+
## Extra Options
|
|
151
|
+
|
|
152
|
+
All repository operations accept an `options` parameter with these fields:
|
|
153
|
+
|
|
154
|
+
| Option | Type | Description |
|
|
155
|
+
| :--- | :--- | :--- |
|
|
156
|
+
| `transaction` | `ITransaction` | Transaction context for atomic operations |
|
|
157
|
+
| `shouldReturn` | `boolean` | Whether to return created/updated data (default: `true`) |
|
|
158
|
+
| `shouldQueryRange` | `boolean` | Return `{ data, range: { total, skip, limit } }` for pagination |
|
|
159
|
+
| `shouldSkipDefaultFilter` | `boolean` | Bypass the model's default filter (e.g., soft delete) |
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Create without returning data (faster for bulk inserts)
|
|
163
|
+
await repo.create({
|
|
164
|
+
data: bulkData,
|
|
165
|
+
options: { shouldReturn: false }
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Query with pagination range
|
|
169
|
+
const result = await repo.find({
|
|
170
|
+
filter: { limit: 20, skip: 0 },
|
|
171
|
+
options: { shouldQueryRange: true }
|
|
172
|
+
});
|
|
173
|
+
// result = { data: [...], range: { total: 150, skip: 0, limit: 20 } }
|
|
174
|
+
```
|
|
175
|
+
|
|
137
176
|
## Querying with Relations
|
|
138
177
|
|
|
139
178
|
Use `include` to fetch related data. The relation name must match what you defined in `static relations`:
|
|
@@ -162,6 +201,34 @@ export class Application extends BaseApplication {
|
|
|
162
201
|
}
|
|
163
202
|
```
|
|
164
203
|
|
|
204
|
+
## SoftDeletableRepository
|
|
205
|
+
|
|
206
|
+
For soft-delete patterns, use `SoftDeletableRepository` which overrides delete operations to set a `deletedAt` timestamp instead of physically removing records:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { SoftDeletableRepository, repository, model, BaseEntity } from '@venizia/ignis';
|
|
210
|
+
import { pgTable, timestamp } from 'drizzle-orm/pg-core';
|
|
211
|
+
|
|
212
|
+
@model({
|
|
213
|
+
type: 'entity',
|
|
214
|
+
settings: {
|
|
215
|
+
hiddenProperties: ['deletedAt'],
|
|
216
|
+
defaultFilter: { where: { deletedAt: null } },
|
|
217
|
+
},
|
|
218
|
+
})
|
|
219
|
+
export class Category extends BaseEntity<typeof Category.schema> {
|
|
220
|
+
static override schema = pgTable('Category', {
|
|
221
|
+
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
222
|
+
...generateTzColumnDefs(),
|
|
223
|
+
deletedAt: timestamp('deleted_at', { withTimezone: true }),
|
|
224
|
+
name: text('name').notNull(),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@repository({ dataSource: PostgresDataSource, model: Category })
|
|
229
|
+
export class CategoryRepository extends SoftDeletableRepository<typeof Category.schema> {}
|
|
230
|
+
```
|
|
231
|
+
|
|
165
232
|
## Repository Template
|
|
166
233
|
|
|
167
234
|
```typescript
|
|
@@ -177,7 +244,7 @@ export class MyModelRepository extends DefaultCRUDRepository<typeof MyModel.sche
|
|
|
177
244
|
|
|
178
245
|
### Performance: Core API Optimization
|
|
179
246
|
|
|
180
|
-
Ignis automatically optimizes "flat" queries (no relations, no field selection) by using Drizzle's Core API. This provides **~15-20% faster** queries for simple reads.
|
|
247
|
+
Ignis automatically optimizes "flat" queries (no relations, no field selection) by using Drizzle's Core API. This provides **~15-20% faster** queries for simple reads. The `canUseCoreAPI()` method on `ReadableRepository` determines when this optimization applies.
|
|
181
248
|
|
|
182
249
|
### Modular Persistence with Components
|
|
183
250
|
|
|
@@ -186,9 +253,9 @@ Bundle related persistence resources into Components for better organization:
|
|
|
186
253
|
```typescript
|
|
187
254
|
export class UserManagementComponent extends BaseComponent {
|
|
188
255
|
override binding() {
|
|
189
|
-
this.
|
|
190
|
-
this.
|
|
191
|
-
this.
|
|
256
|
+
this._application.dataSource(PostgresDataSource);
|
|
257
|
+
this._application.repository(UserRepository);
|
|
258
|
+
this._application.repository(ProfileRepository);
|
|
192
259
|
}
|
|
193
260
|
}
|
|
194
261
|
```
|
|
@@ -4,10 +4,10 @@ Ignis supports explicit transaction objects that can be passed across multiple s
|
|
|
4
4
|
|
|
5
5
|
## Using Transactions
|
|
6
6
|
|
|
7
|
-
To use transactions, start one from a repository
|
|
7
|
+
To use transactions, start one from a datasource (via the repository's `beginTransaction` method), and then pass it to subsequent operations via the `options` parameter.
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
|
-
// 1. Start a transaction
|
|
10
|
+
// 1. Start a transaction from the datasource (accessed through a repository)
|
|
11
11
|
const tx = await userRepo.beginTransaction({
|
|
12
12
|
isolationLevel: 'SERIALIZABLE' // Optional, defaults to 'READ COMMITTED'
|
|
13
13
|
});
|
|
@@ -38,6 +38,20 @@ try {
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Transaction Object
|
|
42
|
+
|
|
43
|
+
The transaction object returned by `beginTransaction()` has the following properties:
|
|
44
|
+
|
|
45
|
+
| Property/Method | Type | Description |
|
|
46
|
+
| :--- | :--- | :--- |
|
|
47
|
+
| `connector` | `TNodePostgresConnector` | A Drizzle connector bound to the transaction's database client |
|
|
48
|
+
| `isolationLevel` | `TIsolationLevel` | The isolation level of this transaction |
|
|
49
|
+
| `isActive` | `boolean` | Whether the transaction is still active (not yet committed/rolled back) |
|
|
50
|
+
| `commit()` | `Promise<void>` | Commit the transaction and release the connection |
|
|
51
|
+
| `rollback()` | `Promise<void>` | Rollback the transaction and release the connection |
|
|
52
|
+
|
|
53
|
+
Calling `commit()` or `rollback()` on an already-ended transaction throws an error.
|
|
54
|
+
|
|
41
55
|
## Isolation Levels
|
|
42
56
|
|
|
43
57
|
Ignis supports standard PostgreSQL isolation levels:
|
|
@@ -48,10 +62,12 @@ Ignis supports standard PostgreSQL isolation levels:
|
|
|
48
62
|
| `REPEATABLE READ` | Queries see a snapshot as of the start of the transaction. | Reports, consistent reads across multiple queries. |
|
|
49
63
|
| `SERIALIZABLE` | Strictest level. Emulates serial execution. | Financial transactions, critical data integrity. |
|
|
50
64
|
|
|
65
|
+
Note: `READ UNCOMMITTED` is technically accepted but behaves as `READ COMMITTED` in PostgreSQL.
|
|
66
|
+
|
|
51
67
|
## Best Practices
|
|
52
68
|
|
|
53
|
-
1. **Always use `try...catch
|
|
54
|
-
2. **Keep it short**: Long-running transactions hold database
|
|
69
|
+
1. **Always use `try...catch`**: Ensure `rollback()` is called on error to release the connection back to the pool.
|
|
70
|
+
2. **Keep it short**: Long-running transactions hold database connections from the pool and can cause connection exhaustion.
|
|
55
71
|
3. **Pass explicit options**: When calling other services inside a transaction, ensure they accept and use the `transaction` option.
|
|
56
72
|
|
|
57
73
|
```typescript
|
|
@@ -109,19 +125,19 @@ export class OrderService extends BaseService {
|
|
|
109
125
|
|
|
110
126
|
```typescript
|
|
111
127
|
@controller({ path: '/orders' })
|
|
112
|
-
export class OrderController extends
|
|
128
|
+
export class OrderController extends BaseRestController {
|
|
113
129
|
constructor(
|
|
114
130
|
@inject({ key: 'repositories.OrderRepository' })
|
|
115
131
|
private _orderRepository: OrderRepository,
|
|
116
132
|
@inject({ key: 'services.OrderService' })
|
|
117
133
|
private _orderService: OrderService,
|
|
118
134
|
) {
|
|
119
|
-
super({ scope: OrderController.name
|
|
135
|
+
super({ scope: OrderController.name });
|
|
120
136
|
}
|
|
121
137
|
|
|
122
138
|
@post({ configs: OrderRoutes.CREATE })
|
|
123
139
|
async createOrder(c: TRouteContext) {
|
|
124
|
-
const body = c.req.valid<{ order: any; items: any[] }>('json');
|
|
140
|
+
const body = c.req.valid<{ order: any; items: any[] }>('json');
|
|
125
141
|
|
|
126
142
|
const tx = await this._orderRepository.beginTransaction({
|
|
127
143
|
isolationLevel: 'SERIALIZABLE',
|
|
@@ -144,6 +160,20 @@ export class OrderController extends BaseController {
|
|
|
144
160
|
}
|
|
145
161
|
```
|
|
146
162
|
|
|
163
|
+
## How Transactions Work Internally
|
|
164
|
+
|
|
165
|
+
When you pass a `transaction` option to a repository method, the repository uses the transaction's `connector` (a Drizzle instance bound to the transaction's `PoolClient`) instead of the default datasource connector. This ensures all operations within the transaction use the same database connection and see a consistent view of the data.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// Inside AbstractRepository (simplified)
|
|
169
|
+
protected resolveConnector(opts?: { transaction?: ITransaction }) {
|
|
170
|
+
if (opts?.transaction) {
|
|
171
|
+
return opts.transaction.connector;
|
|
172
|
+
}
|
|
173
|
+
return this.dataSource.connector;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
147
177
|
> **Deep Dive:** See [Repository Reference](../../../references/base/repositories/) for more transaction options and patterns.
|
|
148
178
|
|
|
149
179
|
## See Also
|
|
@@ -151,7 +181,7 @@ export class OrderController extends BaseController {
|
|
|
151
181
|
- **Related Concepts:**
|
|
152
182
|
- [Repositories](/guides/core-concepts/persistent/repositories) - Provide transaction API
|
|
153
183
|
- [Services](/guides/core-concepts/services) - Orchestrate transactional operations
|
|
154
|
-
- [Controllers](/guides/core-concepts/controllers) - Initiate transactions from HTTP handlers
|
|
184
|
+
- [Controllers](/guides/core-concepts/rest-controllers) - Initiate transactions from HTTP handlers
|
|
155
185
|
- [DataSources](/guides/core-concepts/persistent/datasources) - Database connections
|
|
156
186
|
|
|
157
187
|
- **References:**
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
# Controllers
|
|
1
|
+
# REST Controllers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
REST controllers handle incoming HTTP requests and return JSON responses -- they are your API endpoints. This is the default transport in Ignis and covers the majority of use cases.
|
|
4
4
|
|
|
5
|
-
> **Deep Dive:** See [Controllers Reference](../../references/base/controllers.md) for
|
|
5
|
+
> **Deep Dive:** See [REST Controllers Reference](../../references/base/controllers.md) for the complete API.
|
|
6
6
|
|
|
7
|
-
## Creating a Controller
|
|
7
|
+
## Creating a REST Controller
|
|
8
8
|
|
|
9
|
-
Extend `
|
|
9
|
+
Extend `BaseRestController` and use decorators to define routes:
|
|
10
10
|
|
|
11
11
|
```typescript
|
|
12
|
-
import {
|
|
12
|
+
import { BaseRestController, controller, get, jsonResponse, z, TRouteContext } from '@venizia/ignis';
|
|
13
13
|
import { HTTP } from '@venizia/ignis-helpers';
|
|
14
|
-
import { Context } from 'hono';
|
|
15
14
|
|
|
16
15
|
@controller({ path: '/users' })
|
|
17
|
-
export class UserController extends
|
|
16
|
+
export class UserController extends BaseRestController {
|
|
18
17
|
constructor() {
|
|
19
|
-
//
|
|
20
|
-
super({ scope: UserController.name
|
|
18
|
+
// scope is used for logging; path can be omitted if @controller provides it
|
|
19
|
+
super({ scope: UserController.name });
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
@get({
|
|
@@ -29,12 +28,13 @@ export class UserController extends BaseController {
|
|
|
29
28
|
}),
|
|
30
29
|
},
|
|
31
30
|
})
|
|
32
|
-
getAllUsers(c:
|
|
31
|
+
getAllUsers(c: TRouteContext) {
|
|
33
32
|
return c.json([{ id: '1', name: 'John Doe' }], HTTP.ResultCodes.RS_2.Ok);
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
35
|
```
|
|
37
|
-
|
|
36
|
+
|
|
37
|
+
Notice that the `binding()` method is no longer needed when using decorators. The path is resolved from the `@controller` decorator metadata first, then falls back to the constructor `path` option.
|
|
38
38
|
|
|
39
39
|
## Controller Lifecycle
|
|
40
40
|
|
|
@@ -42,8 +42,8 @@ Controllers have a simple and predictable lifecycle managed by the application.
|
|
|
42
42
|
|
|
43
43
|
| Stage | Method | Description |
|
|
44
44
|
| :--- | :--- | :--- |
|
|
45
|
-
| **1. Instantiation** | `constructor(opts)` | The controller is created by the DI container. Dependencies are injected, and
|
|
46
|
-
| **2. Configuration**| `
|
|
45
|
+
| **1. Instantiation** | `constructor(opts)` | The controller is created by the DI container. Dependencies are injected, and `super()` initializes the internal `OpenAPIHono` router. The `path` is resolved from `@controller` decorator metadata, falling back to the constructor option. |
|
|
46
|
+
| **2. Configuration**| `configure()` | The application calls `configure()` which invokes `binding()` (for manual routes) and `registerRoutesFromRegistry()` (for decorator routes). This method is **idempotent** -- calling it multiple times has no effect after the first call. |
|
|
47
47
|
|
|
48
48
|
## Defining Routes with Decorators (Recommended)
|
|
49
49
|
|
|
@@ -71,14 +71,13 @@ The `opts` object contains a `configs` property that defines the route's path, r
|
|
|
71
71
|
For optimal organization and type safety, define your route configurations in a constant with `as const`. This allows TypeScript to precisely infer the types for your request data and expected responses within your handler methods.
|
|
72
72
|
|
|
73
73
|
```typescript
|
|
74
|
-
import {
|
|
74
|
+
import { BaseRestController, controller, get, post, jsonContent, jsonResponse, TRouteContext } from '@venizia/ignis';
|
|
75
75
|
import { HTTP } from '@venizia/ignis-helpers';
|
|
76
76
|
import { z } from '@hono/zod-openapi';
|
|
77
77
|
|
|
78
78
|
// Define route configs as const for type inference
|
|
79
79
|
const TestRoutes = {
|
|
80
80
|
GET_DATA: {
|
|
81
|
-
method: HTTP.Methods.GET,
|
|
82
81
|
path: '/',
|
|
83
82
|
responses: jsonResponse({
|
|
84
83
|
description: 'A simple message',
|
|
@@ -86,7 +85,6 @@ const TestRoutes = {
|
|
|
86
85
|
}),
|
|
87
86
|
},
|
|
88
87
|
CREATE_ITEM: {
|
|
89
|
-
method: HTTP.Methods.POST,
|
|
90
88
|
path: '/',
|
|
91
89
|
request: {
|
|
92
90
|
body: jsonContent({
|
|
@@ -102,9 +100,9 @@ const TestRoutes = {
|
|
|
102
100
|
} as const; // Crucial for strict type inference!
|
|
103
101
|
|
|
104
102
|
@controller({ path: '/my-items' })
|
|
105
|
-
export class MyItemsController extends
|
|
103
|
+
export class MyItemsController extends BaseRestController {
|
|
106
104
|
constructor() {
|
|
107
|
-
super({ scope: MyItemsController.name
|
|
105
|
+
super({ scope: MyItemsController.name });
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
@get({ configs: TestRoutes.GET_DATA })
|
|
@@ -171,7 +169,7 @@ import { HTTP } from '@venizia/ignis-helpers';
|
|
|
171
169
|
const GetUsersRoute = {
|
|
172
170
|
path: '/',
|
|
173
171
|
method: 'get',
|
|
174
|
-
|
|
172
|
+
authenticate: { strategies: [Authentication.STRATEGY_JWT] },
|
|
175
173
|
responses: jsonResponse({
|
|
176
174
|
description: 'List of all users',
|
|
177
175
|
schema: z.array(z.object({ id: z.number(), name: z.string() })),
|
|
@@ -197,7 +195,7 @@ import { HTTP } from '@venizia/ignis-helpers';
|
|
|
197
195
|
// ... inside the binding() method
|
|
198
196
|
|
|
199
197
|
const GetUserByIdRoute = {
|
|
200
|
-
path: '
|
|
198
|
+
path: '/{id}',
|
|
201
199
|
method: 'get',
|
|
202
200
|
responses: jsonResponse({
|
|
203
201
|
description: 'A single user',
|
|
@@ -264,12 +262,12 @@ The `ControllerFactory.defineCrudController` method automatically sets up the fo
|
|
|
264
262
|
| :--- | :--- | :--- | :--- |
|
|
265
263
|
| `count` | `GET` | `/count` | Get the number of records matching a filter. |
|
|
266
264
|
| `find` | `GET` | `/` | Retrieve all records matching a filter. |
|
|
267
|
-
| `findById` | `GET` |
|
|
265
|
+
| `findById` | `GET` | `/{id}` | Retrieve a single record by its ID. |
|
|
268
266
|
| `findOne` | `GET` | `/find-one` | Retrieve a single record matching a filter. |
|
|
269
267
|
| `create` | `POST` | `/` | Create a new record. |
|
|
270
|
-
| `updateById` | `PATCH` |
|
|
268
|
+
| `updateById` | `PATCH` | `/{id}` | Update a single record by its ID. |
|
|
271
269
|
| `updateBy` | `PATCH` | `/` | Update multiple records matching a `where` filter. |
|
|
272
|
-
| `deleteById` | `DELETE` |
|
|
270
|
+
| `deleteById` | `DELETE` | `/{id}` | Delete a single record by its ID. |
|
|
273
271
|
| `deleteBy` | `DELETE` | `/` | Delete multiple records matching a `where` filter. |
|
|
274
272
|
|
|
275
273
|
:::info Customization
|
|
@@ -357,7 +355,7 @@ export const MainLayout: FC<PropsWithChildren<MainLayoutProps>> = ({ title, chil
|
|
|
357
355
|
</header>
|
|
358
356
|
<main>{children}</main>
|
|
359
357
|
<footer>
|
|
360
|
-
<p
|
|
358
|
+
<p>© 2025 My App</p>
|
|
361
359
|
</footer>
|
|
362
360
|
</body>
|
|
363
361
|
</html>
|
|
@@ -373,7 +371,7 @@ When you define Zod schemas in your route's `request` configuration (whether wit
|
|
|
373
371
|
|
|
374
372
|
```typescript
|
|
375
373
|
import { z } from '@hono/zod-openapi';
|
|
376
|
-
import { jsonContent, put } from '@venizia/ignis';
|
|
374
|
+
import { jsonContent, put, TRouteContext } from '@venizia/ignis';
|
|
377
375
|
import { HTTP } from '@venizia/ignis-helpers';
|
|
378
376
|
|
|
379
377
|
// ... inside a controller class
|
|
@@ -382,8 +380,7 @@ const UserSchema = z.object({ name: z.string(), email: z.string().email() });
|
|
|
382
380
|
|
|
383
381
|
@put({
|
|
384
382
|
configs: {
|
|
385
|
-
path: '
|
|
386
|
-
method: 'put',
|
|
383
|
+
path: '/{id}',
|
|
387
384
|
request: {
|
|
388
385
|
params: z.object({ id: z.string() }),
|
|
389
386
|
query: z.object({ notify: z.string().optional() }),
|
|
@@ -392,7 +389,7 @@ const UserSchema = z.object({ name: z.string(), email: z.string().email() });
|
|
|
392
389
|
// ... responses
|
|
393
390
|
},
|
|
394
391
|
})
|
|
395
|
-
updateUser(c:
|
|
392
|
+
updateUser(c: TRouteContext) {
|
|
396
393
|
// Access validated data from the request
|
|
397
394
|
const { id } = c.req.valid('param');
|
|
398
395
|
const { notify } = c.req.valid('query');
|
|
@@ -417,8 +414,7 @@ import { HTTP } from '@venizia/ignis-helpers';
|
|
|
417
414
|
// ... inside a controller class
|
|
418
415
|
|
|
419
416
|
const UpdateUserConfig = {
|
|
420
|
-
path: '
|
|
421
|
-
method: 'put',
|
|
417
|
+
path: '/{id}',
|
|
422
418
|
request: {
|
|
423
419
|
params: z.object({ id: z.string() }),
|
|
424
420
|
query: z.object({ notify: z.string().optional() }),
|
|
@@ -453,11 +449,12 @@ Using `TRouteContext` provides a typed context object. By using `c.req.valid<T>(
|
|
|
453
449
|
- [Application](/guides/core-concepts/application/) - Registering controllers
|
|
454
450
|
- [Services](/guides/core-concepts/services) - Business logic layer called by controllers
|
|
455
451
|
- [Dependency Injection](/guides/core-concepts/dependency-injection) - Injecting services into controllers
|
|
452
|
+
- [gRPC Controllers](/guides/core-concepts/grpc-controllers) - RPC-based controllers
|
|
456
453
|
|
|
457
454
|
- **References:**
|
|
458
|
-
- [
|
|
455
|
+
- [BaseRestController API](/references/base/controllers) - Complete REST controller API reference
|
|
459
456
|
- [Middlewares](/references/base/middlewares) - Request interceptors
|
|
460
|
-
- [Swagger Component](/
|
|
457
|
+
- [Swagger Component](/extensions/components/swagger) - Auto-generate API docs
|
|
461
458
|
- [Schema Utilities](/references/utilities/schema) - Request/response helpers
|
|
462
459
|
|
|
463
460
|
- **Tutorials:**
|
|
@@ -15,7 +15,7 @@ Services contain the core business logic of your application. They orchestrate t
|
|
|
15
15
|
|
|
16
16
|
### Creating a Service
|
|
17
17
|
|
|
18
|
-
To create a service,
|
|
18
|
+
To create a service, extend the `BaseService` class and inject the repositories or other services it depends on.
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
import { BaseService, inject } from '@venizia/ignis';
|
|
@@ -27,9 +27,9 @@ import { TConfiguration } from '../models/entities';
|
|
|
27
27
|
|
|
28
28
|
export class ConfigurationService extends BaseService {
|
|
29
29
|
constructor(
|
|
30
|
-
@inject({ key: 'repositories.ConfigurationRepository' })
|
|
30
|
+
@inject({ key: 'repositories.ConfigurationRepository' })
|
|
31
31
|
private configurationRepository: ConfigurationRepository,
|
|
32
|
-
@inject({ key: 'repositories.UserRepository' })
|
|
32
|
+
@inject({ key: 'repositories.UserRepository' })
|
|
33
33
|
private userRepository: UserRepository,
|
|
34
34
|
@inject({ key: 'services.LoggingService' })
|
|
35
35
|
private loggingService: LoggingService, // Injecting another service for reuse
|
|
@@ -49,6 +49,20 @@ export class ConfigurationService extends BaseService {
|
|
|
49
49
|
// ...
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### BaseService API
|
|
53
|
+
|
|
54
|
+
`BaseService` is intentionally minimal. It extends `BaseHelper` to provide scoped logging:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
export abstract class BaseService extends BaseHelper implements IService {
|
|
58
|
+
constructor(opts: { scope: string }) {
|
|
59
|
+
super({ scope: opts.scope });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
There is no built-in CRUD service -- implement business logic directly in your service methods. This keeps the service layer focused on your domain-specific operations rather than generic data access patterns (which belong in repositories).
|
|
65
|
+
|
|
52
66
|
## How Services Fit into the Architecture
|
|
53
67
|
|
|
54
68
|
Services act as the primary layer for business logic, sitting between controllers and repositories. While controllers are the typical entry point, **services can also inject and call other services**. This enables powerful logic reuse and allows you to build complex use cases by composing smaller, specialized services.
|
|
@@ -88,14 +102,14 @@ This layered architecture makes your application:
|
|
|
88
102
|
## See Also
|
|
89
103
|
|
|
90
104
|
- **Related Concepts:**
|
|
91
|
-
- [Controllers](/guides/core-concepts/controllers) - Call services to handle requests
|
|
105
|
+
- [Controllers](/guides/core-concepts/rest-controllers) - Call services to handle requests
|
|
92
106
|
- [Repositories](/guides/core-concepts/persistent/repositories) - Data access layer used by services
|
|
93
107
|
- [Dependency Injection](/guides/core-concepts/dependency-injection) - Injecting dependencies into services
|
|
94
108
|
|
|
95
109
|
- **References:**
|
|
96
110
|
- [BaseService API](/references/base/services) - Complete API reference
|
|
97
111
|
- [Providers](/references/base/providers) - Factory pattern for runtime instantiation
|
|
98
|
-
- [Logger Helper](/
|
|
112
|
+
- [Logger Helper](/extensions/helpers/logger/) - Logging in services
|
|
99
113
|
|
|
100
114
|
- **Best Practices:**
|
|
101
115
|
- [Architectural Patterns](/best-practices/architectural-patterns) - Service layer design
|
|
@@ -81,7 +81,7 @@ Create `src/index.ts`:
|
|
|
81
81
|
import { z } from "@hono/zod-openapi";
|
|
82
82
|
import {
|
|
83
83
|
BaseApplication,
|
|
84
|
-
|
|
84
|
+
BaseRestController,
|
|
85
85
|
controller,
|
|
86
86
|
get,
|
|
87
87
|
IApplicationInfo,
|
|
@@ -94,7 +94,7 @@ import appInfo from "./../package.json";
|
|
|
94
94
|
|
|
95
95
|
// 1. Define a controller
|
|
96
96
|
@controller({ path: "/hello" })
|
|
97
|
-
class HelloController extends
|
|
97
|
+
class HelloController extends BaseRestController {
|
|
98
98
|
constructor() {
|
|
99
99
|
super({ scope: "HelloController", path: "/hello" });
|
|
100
100
|
}
|
|
@@ -108,7 +108,6 @@ class HelloController extends BaseController {
|
|
|
108
108
|
@get({
|
|
109
109
|
configs: {
|
|
110
110
|
path: "/",
|
|
111
|
-
method: HTTP.Methods.GET,
|
|
112
111
|
responses: {
|
|
113
112
|
[HTTP.ResultCodes.RS_2.Ok]: jsonContent({
|
|
114
113
|
description: "Says hello",
|
|
@@ -235,10 +234,10 @@ Open `http://localhost:3000/doc/explorer` to see interactive Swagger UI document
|
|
|
235
234
|
|
|
236
235
|
| Component | What It Does |
|
|
237
236
|
|-----------|--------------|
|
|
238
|
-
| `@controller` | Registers a class as an API controller at `/api/hello` |
|
|
239
|
-
| `@get` | Defines a GET endpoint with OpenAPI metadata |
|
|
237
|
+
| `@controller` | Registers a class as an API controller at `/api/hello`. Supports `transport` field for REST (default) or gRPC |
|
|
238
|
+
| `@get` | Defines a GET endpoint with OpenAPI metadata (auto-sets HTTP method) |
|
|
240
239
|
| `Zod schema` | Validates request/response and auto-generates OpenAPI docs |
|
|
241
|
-
| `
|
|
240
|
+
| `BaseRestController` | Provides lifecycle hooks, route binding, and OpenAPI integration for REST controllers |
|
|
242
241
|
| `BaseApplication` | Manages dependency injection, middleware, and server startup |
|
|
243
242
|
| `SwaggerComponent` | Generates interactive API docs at `/doc/explorer` |
|
|
244
243
|
| `app.start()` | Boots the DI container and starts HTTP server on port 3000 |
|
|
@@ -296,7 +295,7 @@ You might wonder why we set up TypeScript, ESLint, and Prettier configs in a "qu
|
|
|
296
295
|
},
|
|
297
296
|
})
|
|
298
297
|
async greet(c: Context) {
|
|
299
|
-
const { name } =
|
|
298
|
+
const { name } = c.req.valid('json');
|
|
300
299
|
return c.json({ greeting: `Hello, ${name}!` }, HTTP.ResultCodes.RS_2.Ok);
|
|
301
300
|
}
|
|
302
301
|
```
|
|
@@ -13,7 +13,7 @@ Ignis combines the structured, enterprise-grade development experience of **Loop
|
|
|
13
13
|
|
|
14
14
|
## The Framework Landscape
|
|
15
15
|
|
|
16
|
-
When building REST APIs with Node.js/Bun, developers choose from three categories of frameworks:
|
|
16
|
+
When building REST APIs and server applications with Node.js/Bun, developers choose from three categories of frameworks:
|
|
17
17
|
|
|
18
18
|
<div class="landscape-grid">
|
|
19
19
|
|
package/wiki/guides/index.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Getting Started with Ignis
|
|
2
2
|
|
|
3
|
-
Welcome to Ignis — a TypeScript framework that combines enterprise architecture patterns with Hono's blazing performance. Whether you're building a SaaS backend, REST API, or microservice, these guides will take you from installation to production-ready code with type-safe database operations, auto-generated OpenAPI docs, and clean dependency injection.
|
|
3
|
+
Welcome to Ignis — a TypeScript framework that combines enterprise architecture patterns with Hono's blazing performance. Whether you're building a SaaS backend, REST API, gRPC service, or microservice, these guides will take you from installation to production-ready code with type-safe database operations, auto-generated OpenAPI docs, and clean dependency injection.
|
|
4
4
|
|
|
5
5
|
<div class="guide-cards">
|
|
6
6
|
|
|
@@ -63,7 +63,7 @@ Welcome to Ignis — a TypeScript framework that combines enterprise architectur
|
|
|
63
63
|
<span class="stage-num">3</span>
|
|
64
64
|
<h4>Understand the Framework</h4>
|
|
65
65
|
</div>
|
|
66
|
-
<p><a href="./core-concepts/application">Application</a> → <a href="./core-concepts/controllers">Controllers</a> → <a href="./core-concepts/services">Services</a> → <a href="./core-concepts/dependency-injection">DI</a></p>
|
|
66
|
+
<p><a href="./core-concepts/application">Application</a> → <a href="./core-concepts/rest-controllers">Controllers</a> → <a href="./core-concepts/services">Services</a> → <a href="./core-concepts/dependency-injection">DI</a></p>
|
|
67
67
|
<span class="stage-desc">Deep dive into core concepts and architecture patterns</span>
|
|
68
68
|
</div>
|
|
69
69
|
|
|
@@ -8,7 +8,7 @@ Quick reference for key terms in Ignis documentation.
|
|
|
8
8
|
| Term | Description |
|
|
9
9
|
|------|-------------|
|
|
10
10
|
| **Application** | Main entry point extending `BaseApplication`. Registers all components. |
|
|
11
|
-
| **Controller** | Handles HTTP requests, defines API endpoints
|
|
11
|
+
| **Controller** | Handles HTTP/gRPC requests, defines API endpoints. REST controllers extend `BaseRestController`, gRPC controllers extend `BaseGrpcController`. Uses `@controller`, `@get`, `@post` decorators |
|
|
12
12
|
| **Service** | Contains business logic between controllers and repositories |
|
|
13
13
|
| **Repository** | Database operations for one entity (`find`, `create`, `updateById`, etc.) |
|
|
14
14
|
| **DataSource** | Database connection configuration (host, port, credentials) |
|
|
@@ -36,7 +36,7 @@ const TodoRoutes = {
|
|
|
36
36
|
} as const;
|
|
37
37
|
|
|
38
38
|
@controller({ path: '/todos' })
|
|
39
|
-
export class TodoController extends
|
|
39
|
+
export class TodoController extends BaseRestController {
|
|
40
40
|
@get({ configs: TodoRoutes.GET_ALL })
|
|
41
41
|
async getAll(c: TRouteContext) {
|
|
42
42
|
const todos = await this.repository.find({});
|
|
@@ -49,7 +49,7 @@ export class TodoController extends BaseController {
|
|
|
49
49
|
export class TodoRepository extends DefaultCRUDRepository<typeof Todo.schema> {}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
**Related:** [Application](../core-concepts/application/) | [Controllers](../core-concepts/controllers) | [Services](../core-concepts/services) | [Repositories](../../references/base/repositories/)
|
|
52
|
+
**Related:** [Application](../core-concepts/application/) | [Controllers](../core-concepts/rest-controllers) | [Services](../core-concepts/services) | [Repositories](../../references/base/repositories/)
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
## TypeScript & Pattern Terms
|
|
@@ -59,7 +59,7 @@ Annotations starting with `@` that add behavior to classes/methods.
|
|
|
59
59
|
|
|
60
60
|
| Decorator | Purpose |
|
|
61
61
|
|-----------|---------|
|
|
62
|
-
| `@controller` | Marks class as controller |
|
|
62
|
+
| `@controller` | Marks class as controller. Supports `transport` field (`'rest'` default, `'grpc'`) |
|
|
63
63
|
| `@model` | Marks class as model/entity |
|
|
64
64
|
| `@repository` | Marks class as repository |
|
|
65
65
|
| `@datasource` | Marks class as datasource |
|
|
@@ -164,7 +164,7 @@ await repository.find({
|
|
|
164
164
|
| Operator | Meaning | Example |
|
|
165
165
|
|----------|---------|---------|
|
|
166
166
|
| `eq` | Equal | `{ status: { eq: 'active' } }` |
|
|
167
|
-
| `
|
|
167
|
+
| `neq` | Not equal | `{ status: { neq: 'deleted' } }` |
|
|
168
168
|
| `gt`, `gte` | Greater than (or equal) | `{ age: { gte: 18 } }` |
|
|
169
169
|
| `lt`, `lte` | Less than (or equal) | `{ price: { lt: 100 } }` |
|
|
170
170
|
| `like`, `ilike` | Pattern match | `{ name: { like: '%john%' } }` |
|
|
@@ -194,7 +194,7 @@ const TodoRoutes = {
|
|
|
194
194
|
} as const;
|
|
195
195
|
|
|
196
196
|
@controller({ path: '/todos' })
|
|
197
|
-
class TodoController {
|
|
197
|
+
class TodoController extends BaseRestController {
|
|
198
198
|
@get({ configs: TodoRoutes.GET_ALL })
|
|
199
199
|
async getAll(c: TRouteContext) { ... }
|
|
200
200
|
|
|
@@ -217,7 +217,7 @@ class TodoController {
|
|
|
217
217
|
| **Endpoint** | URL path that API responds to (e.g., `GET /todos`) |
|
|
218
218
|
| **Route Parameter** | Variable in URL marked with `:` (e.g., `:id`) |
|
|
219
219
|
| **Request Body** | JSON data sent with POST/PATCH requests |
|
|
220
|
-
| **OpenAPI/Swagger** | Auto-generated API docs at `/
|
|
220
|
+
| **OpenAPI/Swagger** | Auto-generated API docs at `/doc/explorer` (default path via SwaggerComponent) |
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
## Environment & Configuration
|
|
@@ -755,7 +755,7 @@ If this works, the issue is specific to `@venizia/ignis-docs`.
|
|
|
755
755
|
|
|
756
756
|
## What's Next?
|
|
757
757
|
|
|
758
|
-
- **Learn the Tools:** Read the [Deep Dive Guide](/
|
|
758
|
+
- **Learn the Tools:** Read the [Deep Dive Guide](/extensions/src-details/mcp-server) to understand all 5 available tools
|
|
759
759
|
- **Advanced Usage:** Explore how to chain tools for complex documentation queries
|
|
760
760
|
- **Contribute:** Help improve the docs or add new features
|
|
761
761
|
|
|
@@ -598,7 +598,7 @@ this.controller(TodoController); // ← Make sure this is here!
|
|
|
598
598
|
path: { base: '/api', isStrict: true }, // All routes start with /api
|
|
599
599
|
```
|
|
600
600
|
|
|
601
|
-
**Debug:** Set `debug
|
|
601
|
+
**Debug:** Set `debug: { shouldShowRoutes: true }` in appConfigs to see all registered routes on startup.
|
|
602
602
|
|
|
603
603
|
|
|
604
604
|
### Error: "Invalid JSON" when creating todo
|
|
@@ -695,7 +695,7 @@ You now have a fully functional CRUD API! Here's what to explore next:
|
|
|
695
695
|
3. [Components](../core-concepts/components.md) - Build reusable modules
|
|
696
696
|
|
|
697
697
|
**Add Features:**
|
|
698
|
-
1. [Authentication](/
|
|
698
|
+
1. [Authentication](/extensions/components/authentication/) - Add JWT authentication
|
|
699
699
|
2. [Custom Routes](/best-practices/api-usage-examples.md) - Beyond CRUD operations
|
|
700
700
|
3. [Relationships](../core-concepts/persistent/) - Link todos to users
|
|
701
701
|
|