@venizia/ignis-docs 0.0.8-3 → 0.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 +7 -7
- package/{wiki → content}/best-practices/api-usage-examples.md +15 -12
- package/{wiki → content}/best-practices/architectural-patterns.md +70 -78
- package/{wiki → content}/best-practices/architecture-decisions.md +91 -60
- package/{wiki → content}/best-practices/code-style-standards/advanced-patterns.md +56 -44
- package/{wiki → content}/best-practices/code-style-standards/constants-configuration.md +11 -11
- package/{wiki → content}/best-practices/code-style-standards/control-flow.md +5 -2
- package/{wiki → content}/best-practices/code-style-standards/documentation.md +13 -13
- package/{wiki → content}/best-practices/code-style-standards/function-patterns.md +9 -10
- package/{wiki → content}/best-practices/code-style-standards/index.md +1 -1
- package/{wiki → content}/best-practices/code-style-standards/naming-conventions.md +10 -8
- package/{wiki → content}/best-practices/code-style-standards/route-definitions.md +30 -12
- package/{wiki → content}/best-practices/code-style-standards/tooling.md +8 -5
- package/{wiki → content}/best-practices/code-style-standards/type-safety.md +13 -12
- package/{wiki → content}/best-practices/common-pitfalls.md +56 -37
- package/{wiki → content}/best-practices/contribution-workflow.md +13 -14
- package/{wiki → content}/best-practices/data-modeling.md +44 -20
- package/{wiki → content}/best-practices/deployment-strategies.md +28 -27
- package/{wiki → content}/best-practices/error-handling.md +48 -24
- package/{wiki → content}/best-practices/index.md +5 -5
- package/{wiki → content}/best-practices/performance-optimization.md +36 -28
- package/{wiki → content}/best-practices/security-guidelines.md +52 -23
- package/{wiki → content}/best-practices/testing-strategies.md +65 -51
- package/{wiki → content}/best-practices/troubleshooting-tips.md +24 -24
- package/{wiki/extensions/components/swagger.md → content/extensions/components/api-reference.md} +40 -31
- package/{wiki → content}/extensions/components/authentication/api.md +19 -19
- package/{wiki → content}/extensions/components/authentication/errors.md +7 -7
- package/{wiki → content}/extensions/components/authentication/index.md +10 -8
- package/{wiki → content}/extensions/components/authentication/usage.md +101 -6
- package/{wiki → content}/extensions/components/authorization/api.md +45 -25
- package/{wiki → content}/extensions/components/authorization/errors.md +6 -6
- package/{wiki → content}/extensions/components/authorization/index.md +11 -10
- package/{wiki → content}/extensions/components/authorization/usage.md +21 -21
- package/{wiki → content}/extensions/components/health-check.md +1 -1
- package/{wiki → content}/extensions/components/index.md +5 -5
- package/{wiki → content}/extensions/components/mail/errors.md +15 -15
- package/{wiki → content}/extensions/components/mail/index.md +1 -2
- package/{wiki → content}/extensions/components/mail/usage.md +1 -1
- package/{wiki → content}/extensions/components/request-tracker.md +1 -1
- package/{wiki → content}/extensions/components/socket-io/api.md +9 -9
- package/{wiki → content}/extensions/components/socket-io/errors.md +5 -5
- package/{wiki → content}/extensions/components/socket-io/index.md +8 -8
- package/{wiki → content}/extensions/components/socket-io/usage.md +1 -1
- package/{wiki → content}/extensions/components/static-asset/api.md +17 -4
- package/{wiki → content}/extensions/components/static-asset/errors.md +4 -4
- package/{wiki → content}/extensions/components/static-asset/index.md +26 -28
- package/{wiki → content}/extensions/components/static-asset/usage.md +13 -12
- package/{wiki → content}/extensions/components/template/index.md +2 -2
- package/{wiki → content}/extensions/components/template/setup-page.md +1 -1
- package/{wiki → content}/extensions/components/websocket/api.md +3 -3
- package/{wiki → content}/extensions/components/websocket/errors.md +5 -5
- package/{wiki → content}/extensions/components/websocket/index.md +5 -5
- package/{wiki → content}/extensions/components/websocket/usage.md +3 -3
- package/{wiki → content}/extensions/helpers/cron/index.md +2 -2
- package/{wiki → content}/extensions/helpers/crypto/index.md +1 -1
- package/{wiki → content}/extensions/helpers/env/index.md +27 -12
- package/content/extensions/helpers/error/index.md +283 -0
- package/{wiki → content}/extensions/helpers/index.md +2 -3
- package/{wiki → content}/extensions/helpers/inversion/index.md +15 -7
- package/{wiki → content}/extensions/helpers/kafka/examples.md +1 -1
- package/{wiki → content}/extensions/helpers/logger/index.md +32 -2
- package/{wiki → content}/extensions/helpers/network/index.md +6 -0
- package/{wiki → content}/extensions/helpers/queue/index.md +14 -17
- package/content/extensions/helpers/redis/index.md +713 -0
- package/{wiki → content}/extensions/helpers/socket-io/index.md +14 -10
- package/{wiki → content}/extensions/helpers/storage/api.md +44 -8
- package/{wiki → content}/extensions/helpers/storage/index.md +43 -7
- package/{wiki → content}/extensions/helpers/template/index.md +6 -3
- package/{wiki → content}/extensions/helpers/types/index.md +11 -8
- package/{wiki → content}/extensions/helpers/websocket/api.md +9 -9
- package/{wiki → content}/extensions/helpers/websocket/index.md +7 -7
- package/{wiki → content}/extensions/helpers/worker-thread/index.md +2 -2
- package/{wiki → content}/extensions/index.md +3 -4
- package/{wiki → content}/extensions/src-details/mcp-server.md +18 -24
- package/{wiki → content}/guides/core-concepts/application/bootstrapping.md +11 -14
- package/{wiki → content}/guides/core-concepts/application/index.md +3 -3
- package/{wiki → content}/guides/core-concepts/components.md +19 -10
- package/{wiki → content}/guides/core-concepts/dependency-injection.md +6 -3
- package/{wiki → content}/guides/core-concepts/grpc-controllers.md +6 -5
- package/{wiki → content}/guides/core-concepts/persistent/datasources.md +33 -27
- package/{wiki → content}/guides/core-concepts/persistent/index.md +16 -5
- package/{wiki → content}/guides/core-concepts/persistent/models.md +24 -20
- package/content/guides/core-concepts/persistent/postgres-drivers.md +167 -0
- package/{wiki → content}/guides/core-concepts/persistent/repositories.md +40 -23
- package/content/guides/core-concepts/persistent/search-meilisearch.md +183 -0
- package/content/guides/core-concepts/persistent/search-typesense.md +429 -0
- package/{wiki → content}/guides/core-concepts/persistent/transactions.md +61 -25
- package/{wiki → content}/guides/core-concepts/rest-controllers.md +12 -9
- package/content/guides/core-concepts/services.md +389 -0
- package/{wiki → content}/guides/get-started/5-minute-quickstart.md +19 -19
- package/{wiki → content}/guides/get-started/philosophy.md +36 -36
- package/{wiki → content}/guides/get-started/setup.md +3 -3
- package/{wiki → content}/guides/index.md +3 -3
- package/content/guides/migrations/redis-helpers-migration.md +177 -0
- package/{wiki → content}/guides/migrations/scoped-rbac-migration.md +17 -17
- package/content/guides/migrations/unified-connectors-migration.md +113 -0
- package/{wiki → content}/guides/reference/glossary.md +19 -12
- package/{wiki → content}/guides/reference/mcp-docs-server.md +22 -18
- package/{wiki → content}/guides/tutorials/building-a-crud-api.md +30 -33
- package/{wiki → content}/guides/tutorials/complete-installation.md +17 -17
- package/{wiki → content}/guides/tutorials/ecommerce-api.md +158 -119
- package/{wiki → content}/guides/tutorials/realtime-chat.md +176 -130
- package/content/guides/tutorials/testing.md +264 -0
- package/content/index.md +5 -0
- package/content/public/apple-touch-icon.png +0 -0
- package/content/public/og-image.png +0 -0
- package/content/public/site.webmanifest +11 -0
- package/{wiki → content}/references/base/application.md +4 -5
- package/{wiki → content}/references/base/bootstrapping.md +18 -5
- package/{wiki → content}/references/base/components.md +149 -120
- package/content/references/base/connectors.md +178 -0
- package/{wiki → content}/references/base/controllers.md +41 -30
- package/content/references/base/datasources.md +527 -0
- package/{wiki → content}/references/base/dependency-injection.md +34 -22
- package/{wiki → content}/references/base/filter-system/application-usage.md +17 -14
- package/{wiki → content}/references/base/filter-system/array-operators.md +7 -2
- package/{wiki → content}/references/base/filter-system/comparison-operators.md +3 -0
- package/{wiki → content}/references/base/filter-system/default-filter.md +89 -71
- package/{wiki → content}/references/base/filter-system/fields-order-pagination.md +22 -22
- package/{wiki → content}/references/base/filter-system/index.md +6 -3
- package/{wiki → content}/references/base/filter-system/json-filtering.md +20 -1
- package/{wiki → content}/references/base/filter-system/list-operators.md +1 -1
- package/{wiki → content}/references/base/filter-system/logical-operators.md +33 -1
- package/{wiki → content}/references/base/filter-system/null-operators.md +30 -1
- package/{wiki → content}/references/base/filter-system/quick-reference.md +23 -4
- package/{wiki → content}/references/base/filter-system/tips.md +5 -5
- package/{wiki → content}/references/base/filter-system/use-cases.md +12 -12
- package/{wiki → content}/references/base/grpc-controllers.md +13 -13
- package/{wiki → content}/references/base/index.md +24 -12
- package/{wiki/references/base/middleware.md → content/references/base/middlewares.md} +205 -24
- package/{wiki → content}/references/base/models.md +63 -49
- package/{wiki → content}/references/base/providers.md +136 -130
- package/{wiki → content}/references/base/repositories/advanced.md +59 -58
- package/{wiki → content}/references/base/repositories/index.md +115 -91
- package/content/references/base/repositories/mixins.md +99 -0
- package/{wiki → content}/references/base/repositories/relations.md +54 -64
- package/{wiki → content}/references/base/repositories/soft-deletable.md +31 -30
- package/content/references/base/services.md +404 -0
- package/{wiki → content}/references/configuration/environment-variables.md +46 -30
- package/{wiki → content}/references/configuration/index.md +6 -6
- package/{wiki → content}/references/index.md +17 -12
- package/{wiki → content}/references/quick-reference.md +65 -106
- package/content/references/utilities/crypto.md +98 -0
- package/{wiki → content}/references/utilities/index.md +3 -3
- package/{wiki → content}/references/utilities/jsx.md +6 -4
- package/content/references/utilities/module.md +90 -0
- package/{wiki → content}/references/utilities/parse.md +4 -14
- package/{wiki → content}/references/utilities/promise.md +9 -7
- package/{wiki → content}/references/utilities/schema.md +5 -3
- package/dist/mcp-server/common/guards.d.ts +8 -0
- package/dist/mcp-server/common/guards.d.ts.map +1 -0
- package/dist/mcp-server/common/guards.js +14 -0
- package/dist/mcp-server/common/guards.js.map +1 -0
- package/dist/mcp-server/common/index.d.ts +1 -0
- package/dist/mcp-server/common/index.d.ts.map +1 -1
- package/dist/mcp-server/common/index.js +1 -0
- package/dist/mcp-server/common/index.js.map +1 -1
- package/dist/mcp-server/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +2 -2
- package/dist/mcp-server/common/paths.js.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.js +4 -2
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/dist/mcp-server/helpers/github.helper.js +1 -1
- package/dist/mcp-server/index.js +7 -2
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +6 -2
- package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/base.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
- package/package.json +12 -12
- package/wiki/extensions/helpers/error/index.md +0 -227
- package/wiki/extensions/helpers/redis/index.md +0 -488
- package/wiki/extensions/helpers/testing/index.md +0 -510
- package/wiki/guides/core-concepts/services.md +0 -119
- package/wiki/guides/tutorials/testing.md +0 -722
- package/wiki/index.md +0 -183
- package/wiki/references/base/datasources.md +0 -454
- package/wiki/references/base/middlewares.md +0 -590
- package/wiki/references/base/repositories/mixins.md +0 -335
- package/wiki/references/base/services.md +0 -201
- package/wiki/references/utilities/crypto.md +0 -56
- package/wiki/references/utilities/module.md +0 -42
- /package/{wiki → content}/extensions/components/mail/api.md +0 -0
- /package/{wiki → content}/extensions/components/template/api-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/errors-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/usage-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/admin.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/consumer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/index.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/producer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/schema-registry.md +0 -0
- /package/{wiki → content}/extensions/helpers/network/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/socket-io/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/uid/index.md +0 -0
- /package/{wiki → content}/guides/core-concepts/components-guide.md +0 -0
- /package/{wiki → content}/public/logo.svg +0 -0
- /package/{wiki → content}/references/base/filter-system/pattern-matching.md +0 -0
- /package/{wiki → content}/references/base/filter-system/range-operators.md +0 -0
- /package/{wiki → content}/references/utilities/date.md +0 -0
- /package/{wiki → content}/references/utilities/performance.md +0 -0
- /package/{wiki → content}/references/utilities/request.md +0 -0
- /package/{wiki → content}/references/utilities/statuses.md +0 -0
|
@@ -1,590 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Middlewares Reference
|
|
3
|
-
description: Technical reference for IGNIS built-in middlewares
|
|
4
|
-
difficulty: intermediate
|
|
5
|
-
lastUpdated: 2026-01-03
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Middlewares Reference
|
|
9
|
-
|
|
10
|
-
IGNIS provides a collection of built-in middlewares for common application needs including error handling, request logging, and favicon serving.
|
|
11
|
-
|
|
12
|
-
**Files:**
|
|
13
|
-
- `packages/core/src/base/middlewares/*.ts`
|
|
14
|
-
|
|
15
|
-
## Prerequisites
|
|
16
|
-
|
|
17
|
-
- [Hono Middleware basics](https://hono.dev/docs/guides/middleware)
|
|
18
|
-
- [IGNIS Application basics](./application.md)
|
|
19
|
-
- Basic understanding of HTTP request/response lifecycle
|
|
20
|
-
|
|
21
|
-
## Quick Reference
|
|
22
|
-
|
|
23
|
-
| Middleware | Purpose | Key Options |
|
|
24
|
-
|------------|---------|-------------|
|
|
25
|
-
| `appErrorHandler` | Catches and formats application errors | `logger` |
|
|
26
|
-
| `notFoundHandler` | Handles 404 Not Found responses | `logger` |
|
|
27
|
-
| `RequestSpyMiddleware` | Logs request lifecycle, timing, and parses request body | None |
|
|
28
|
-
| `emojiFavicon` | Serves an emoji as favicon | `icon` |
|
|
29
|
-
|
|
30
|
-
## Table of Contents
|
|
31
|
-
|
|
32
|
-
- [Error Handler (`appErrorHandler`)](#error-handler-apporerrorhandler)
|
|
33
|
-
- [Not Found Handler (`notFoundHandler`)](#not-found-handler-notfoundhandler)
|
|
34
|
-
- [Request Spy (`RequestSpyMiddleware`)](#request-spy-requestspymiddleware)
|
|
35
|
-
- [Emoji Favicon](#emoji-favicon)
|
|
36
|
-
- [Creating Custom Middleware](#creating-custom-middleware)
|
|
37
|
-
- [Middleware Order & Priority](#middleware-order--priority)
|
|
38
|
-
- [See Also](#see-also)
|
|
39
|
-
|
|
40
|
-
## Built-in Middlewares
|
|
41
|
-
|
|
42
|
-
### Error Handler (`appErrorHandler`)
|
|
43
|
-
|
|
44
|
-
The error handler middleware catches all unhandled errors in your application and formats them into consistent JSON responses.
|
|
45
|
-
|
|
46
|
-
**File:** `packages/core/src/base/middlewares/app-error/app-error.middleware.ts`
|
|
47
|
-
|
|
48
|
-
#### Features
|
|
49
|
-
|
|
50
|
-
- **Automatic Error Formatting**: Converts all errors to structured JSON responses
|
|
51
|
-
- **ZodError Support**: Validation errors surface a schema-driven `messageCode` and `message` (from `params.code`, else the raw Zod code), with the full per-field list under `details.cause`
|
|
52
|
-
- **Database Error Handling**: Returns 400 for SQLSTATE class `22` (data exception) and `23` (integrity) errors, with a fallback message; other classes (e.g. `42` programming errors) stay 500
|
|
53
|
-
- **Production-Safe**: Hides stack traces, error causes, DB driver internals (`detail`/`table`/`constraint`), and raw system messages in production
|
|
54
|
-
- **Request Tracking**: Includes `requestId` for debugging and tracing
|
|
55
|
-
- **Status Code Detection**: Automatically extracts `statusCode` from errors
|
|
56
|
-
|
|
57
|
-
#### Usage
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import { appErrorHandler } from '@venizia/ignis';
|
|
61
|
-
|
|
62
|
-
const app = new IgnisApplication({
|
|
63
|
-
// ...
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Register error handler
|
|
67
|
-
app.onError(appErrorHandler({
|
|
68
|
-
logger: app.logger
|
|
69
|
-
}));
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
#### Error Response Format
|
|
73
|
-
|
|
74
|
-
**Standard Error:**
|
|
75
|
-
```json
|
|
76
|
-
{
|
|
77
|
-
"message": "Something went wrong",
|
|
78
|
-
"statusCode": 500,
|
|
79
|
-
"requestId": "abc123",
|
|
80
|
-
"details": {
|
|
81
|
-
"url": "http://localhost:3000/api/users",
|
|
82
|
-
"path": "/api/users",
|
|
83
|
-
"stack": "Error: Something went wrong\n at ...", // development only
|
|
84
|
-
"cause": { ... } // development only
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
**Validation Error (ZodError):**
|
|
90
|
-
|
|
91
|
-
Top-level `message`/`messageCode` come from the first failing issue — its `params.code` if the schema set one (see below), otherwise its raw Zod code. The full per-field list stays under `details.cause`. If `error.rootKey` is configured, the whole body is wrapped under that key.
|
|
92
|
-
|
|
93
|
-
```json
|
|
94
|
-
{
|
|
95
|
-
"message": "Invalid email address",
|
|
96
|
-
"messageCode": "invalid_type",
|
|
97
|
-
"statusCode": 422,
|
|
98
|
-
"requestId": "abc123",
|
|
99
|
-
"details": {
|
|
100
|
-
"url": "http://localhost:3000/api/users",
|
|
101
|
-
"path": "/api/users",
|
|
102
|
-
"stack": "...", // development only
|
|
103
|
-
"cause": [
|
|
104
|
-
{
|
|
105
|
-
"path": "email",
|
|
106
|
-
"message": "Invalid email address",
|
|
107
|
-
"code": "invalid_type",
|
|
108
|
-
"expected": "string"
|
|
109
|
-
}
|
|
110
|
-
]
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
To emit a stable, domain-specific `messageCode`, attach `params.code` to a custom check:
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
z.string().refine(isEmail, { message: 'Invalid email address', params: { code: 'user.email.invalid' } });
|
|
119
|
-
// → "messageCode": "user.email.invalid"
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Database Constraint Error:**
|
|
123
|
-
|
|
124
|
-
Database errors in SQLSTATE class `22` (data exception) and `23` (integrity constraint) are detected by **class** and returned as 400 Bad Request. A known code uses its specific message; any other in-class code uses `DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE` (`"Invalid database request"`).
|
|
125
|
-
|
|
126
|
-
```json
|
|
127
|
-
// non-production — full driver context for debugging
|
|
128
|
-
{
|
|
129
|
-
"message": "Unique constraint violation\nDetail: Key (email)=(test@example.com) already exists.\nTable: User\nConstraint: UQ_User_email",
|
|
130
|
-
"statusCode": 400,
|
|
131
|
-
"requestId": "abc123",
|
|
132
|
-
"details": { "url": "...", "path": "/api/users", "stack": "...", "cause": { } }
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
:::warning Production sanitizes database internals
|
|
137
|
-
In **production** the message is the base message only — `Detail:`/`Table:`/`Constraint:` are stripped (they echo row values and schema names), and `details.stack`/`details.cause` are omitted. Codes outside class 22/23 (e.g. `42703` undefined column) and connection failures return a generic `"Internal Server Error"`, so SQL, schema names, and connection host/port never leak.
|
|
138
|
-
:::
|
|
139
|
-
|
|
140
|
-
**Database client error classes** — codes in SQLSTATE class `22` (data exception), `23` (integrity constraint), and `44` (WITH CHECK OPTION) map to HTTP 400. Common codes get a specific message; any other in-class code uses the fallback (`"Invalid database request"`).
|
|
141
|
-
|
|
142
|
-
| Class | Codes with a specific message |
|
|
143
|
-
|-------|-------------------------------|
|
|
144
|
-
| `23` Integrity | `23505` unique · `23503` foreign key · `23502` not null · `23514` check · `23P01` exclusion · `23000` integrity · `23001` restrict |
|
|
145
|
-
| `22` Data exception | `22001` string too long · `22003` numeric range · `22004` null not allowed · `22007` datetime format · `22008` datetime overflow · `22009` tz displacement · `22011` substring · `22012` division by zero · `22023` invalid parameter · `22025` invalid escape · `22026` length mismatch · `22030` duplicate JSON key · `22032` invalid JSON · `22P01` floating-point · `22P02` invalid text · `22P03` invalid binary · `22P05` untranslatable char |
|
|
146
|
-
| `44` View check | `44000` WITH CHECK OPTION violation |
|
|
147
|
-
|
|
148
|
-
:::tip Transient conflicts return 409, not 400/500
|
|
149
|
-
Class `40` (`40001` serialization failure, `40P01` deadlock) is **transient/retryable** and returns **409 Conflict** with `messageCode: "database.conflict"` and a safe "please retry" message — the client can safely retry the same request. Programming/infra classes (`42` syntax, `53` resources, `0A`, `25`, `28`) remain 500.
|
|
150
|
-
:::
|
|
151
|
-
|
|
152
|
-
#### API Reference
|
|
153
|
-
|
|
154
|
-
##### `appErrorHandler(options)`
|
|
155
|
-
|
|
156
|
-
**Parameters:**
|
|
157
|
-
| Option | Type | Required | Description |
|
|
158
|
-
|--------|------|----------|-------------|
|
|
159
|
-
| `logger` | `ApplicationLogger` | Yes | Logger instance for error logging |
|
|
160
|
-
|
|
161
|
-
**Returns:** `ErrorHandler` - Hono error handler function
|
|
162
|
-
|
|
163
|
-
#### Common Patterns
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
// Custom error with status code
|
|
167
|
-
class NotFoundError extends Error {
|
|
168
|
-
statusCode = 404;
|
|
169
|
-
|
|
170
|
-
constructor(message: string) {
|
|
171
|
-
super(message);
|
|
172
|
-
this.name = 'NotFoundError';
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Throw in controller
|
|
177
|
-
const GetUserConfig = {
|
|
178
|
-
method: HTTP.Methods.GET,
|
|
179
|
-
path: '/users/:id',
|
|
180
|
-
request: {
|
|
181
|
-
params: z.object({ id: z.string() }),
|
|
182
|
-
},
|
|
183
|
-
responses: jsonResponse({
|
|
184
|
-
schema: z.object({ id: z.string(), name: z.string() }),
|
|
185
|
-
}),
|
|
186
|
-
} as const;
|
|
187
|
-
|
|
188
|
-
@get({ configs: GetUserConfig })
|
|
189
|
-
async getUser(c: TRouteContext) {
|
|
190
|
-
const { id } = c.req.valid<{ id: string }>('param');
|
|
191
|
-
const user = await this.userRepository.findById(id);
|
|
192
|
-
if (!user) {
|
|
193
|
-
throw new NotFoundError(`User ${id} not found`);
|
|
194
|
-
}
|
|
195
|
-
return c.json(user, HTTP.ResultCodes.RS_2.Ok);
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
### Not Found Handler (`notFoundHandler`)
|
|
201
|
-
|
|
202
|
-
Handles requests to routes that don't exist, returning a standardized 404 response.
|
|
203
|
-
|
|
204
|
-
**File:** `packages/core/src/base/middlewares/not-found.middleware.ts`
|
|
205
|
-
|
|
206
|
-
#### Usage
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
import { notFoundHandler } from '@venizia/ignis';
|
|
210
|
-
|
|
211
|
-
const app = new IgnisApplication({
|
|
212
|
-
// ...
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// Register 404 handler
|
|
216
|
-
app.notFound(notFoundHandler({
|
|
217
|
-
logger: app.logger
|
|
218
|
-
}));
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
#### Response Format
|
|
222
|
-
|
|
223
|
-
```json
|
|
224
|
-
{
|
|
225
|
-
"message": "URL NOT FOUND",
|
|
226
|
-
"path": "/api/nonexistent",
|
|
227
|
-
"url": "http://localhost:3000/api/nonexistent"
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
**Status Code:** `404 Not Found`
|
|
232
|
-
|
|
233
|
-
#### API Reference
|
|
234
|
-
|
|
235
|
-
##### `notFoundHandler(options)`
|
|
236
|
-
|
|
237
|
-
**Parameters:**
|
|
238
|
-
| Option | Type | Required | Default | Description |
|
|
239
|
-
|--------|------|----------|---------|-------------|
|
|
240
|
-
| `logger` | `ApplicationLogger` | No | `console` | Logger instance for logging 404s |
|
|
241
|
-
|
|
242
|
-
**Returns:** `NotFoundHandler` - Hono not found handler function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
### Request Spy (`RequestSpyMiddleware`)
|
|
246
|
-
|
|
247
|
-
Logs detailed information about each request including timing, IP address, method, path, query parameters, and request body. Also handles request body parsing for JSON, form data, and text content types.
|
|
248
|
-
|
|
249
|
-
**File:** `packages/core/src/base/middlewares/request-spy.middleware.ts`
|
|
250
|
-
|
|
251
|
-
#### Features
|
|
252
|
-
|
|
253
|
-
- Request lifecycle logging (incoming/outgoing)
|
|
254
|
-
- Performance timing tracking
|
|
255
|
-
- IP address extraction (supports `x-real-ip` and `x-forwarded-for` headers)
|
|
256
|
-
- Request ID tracking
|
|
257
|
-
- Query and body parameter logging (body only logged in non-production)
|
|
258
|
-
- **Request body parsing**: Automatically parses and caches request bodies:
|
|
259
|
-
- `application/json` → `req.json()`
|
|
260
|
-
- `multipart/form-data`, `application/x-www-form-urlencoded` → `req.parseBody()`
|
|
261
|
-
- Other content types (text, html, xml) → `req.text()`
|
|
262
|
-
|
|
263
|
-
#### Usage
|
|
264
|
-
|
|
265
|
-
```typescript
|
|
266
|
-
import { RequestSpyMiddleware } from '@venizia/ignis';
|
|
267
|
-
|
|
268
|
-
const app = new IgnisApplication({
|
|
269
|
-
// ...
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// Create and register spy middleware
|
|
273
|
-
const requestSpy = new RequestSpyMiddleware();
|
|
274
|
-
app.use(requestSpy.value());
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
#### Log Output
|
|
278
|
-
|
|
279
|
-
**Request Start:**
|
|
280
|
-
```
|
|
281
|
-
[spy][abc123] START | Handling Request | forwardedIp: 192.168.1.1 | path: /api/users | method: GET
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
**Request Complete:**
|
|
285
|
-
```
|
|
286
|
-
[spy][abc123] DONE | Handling Request | forwardedIp: 192.168.1.1 | path: /api/users | method: GET | Took: 45.23 (ms)
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
#### API Reference
|
|
290
|
-
|
|
291
|
-
##### `RequestSpyMiddleware`
|
|
292
|
-
|
|
293
|
-
**Class Methods:**
|
|
294
|
-
| Method | Returns | Description |
|
|
295
|
-
|--------|---------|-------------|
|
|
296
|
-
| `value()` | `MiddlewareHandler` | Returns the middleware handler |
|
|
297
|
-
|
|
298
|
-
**Static Properties:**
|
|
299
|
-
| Property | Type | Value | Description |
|
|
300
|
-
|----------|------|-------|-------------|
|
|
301
|
-
| `REQUEST_ID_KEY` | `string` | `'requestId'` | Context key for request ID |
|
|
302
|
-
|
|
303
|
-
#### Accessing Request ID
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
import { RequestSpyMiddleware, get, jsonResponse, TRouteContext, z } from '@venizia/ignis';
|
|
307
|
-
import { HTTP } from '@venizia/ignis-helpers';
|
|
308
|
-
|
|
309
|
-
const ExampleConfig = {
|
|
310
|
-
method: HTTP.Methods.GET,
|
|
311
|
-
path: '/example',
|
|
312
|
-
responses: jsonResponse({
|
|
313
|
-
schema: z.object({ requestId: z.string() }),
|
|
314
|
-
}),
|
|
315
|
-
} as const;
|
|
316
|
-
|
|
317
|
-
// In a controller
|
|
318
|
-
@get({ configs: ExampleConfig })
|
|
319
|
-
async example(c: TRouteContext) {
|
|
320
|
-
const requestId = c.get(RequestSpyMiddleware.REQUEST_ID_KEY);
|
|
321
|
-
console.log('Request ID:', requestId);
|
|
322
|
-
return c.json({ requestId }, HTTP.ResultCodes.RS_2.Ok);
|
|
323
|
-
}
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
:::warning Performance Impact
|
|
327
|
-
Request spy logs every request detail. Consider disabling or reducing verbosity in production environments with high traffic.
|
|
328
|
-
:::
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
### Emoji Favicon
|
|
332
|
-
|
|
333
|
-
Serves an SVG emoji as the application's favicon, providing a lightweight alternative to traditional favicon files.
|
|
334
|
-
|
|
335
|
-
**File:** `packages/core/src/base/middlewares/emoji-favicon.middleware.ts`
|
|
336
|
-
|
|
337
|
-
#### Usage
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
import { emojiFavicon } from '@venizia/ignis';
|
|
341
|
-
|
|
342
|
-
const app = new IgnisApplication({
|
|
343
|
-
// ...
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
// Serve a rocket emoji as favicon
|
|
347
|
-
app.use(emojiFavicon({ icon: '🚀' }));
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
#### How It Works
|
|
351
|
-
|
|
352
|
-
1. Intercepts requests to `/favicon.ico`
|
|
353
|
-
2. Returns an inline SVG with the specified emoji
|
|
354
|
-
3. Sets `Content-Type: image/svg+xml`
|
|
355
|
-
4. All other requests pass through unchanged
|
|
356
|
-
|
|
357
|
-
#### API Reference
|
|
358
|
-
|
|
359
|
-
##### `emojiFavicon(options)`
|
|
360
|
-
|
|
361
|
-
**Parameters:**
|
|
362
|
-
| Option | Type | Required | Description |
|
|
363
|
-
|--------|------|----------|-------------|
|
|
364
|
-
| `icon` | `string` | Yes | Emoji character to use as favicon |
|
|
365
|
-
|
|
366
|
-
**Returns:** `MiddlewareHandler` - Hono middleware function
|
|
367
|
-
|
|
368
|
-
#### Examples
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
// Different emoji icons
|
|
372
|
-
app.use(emojiFavicon({ icon: '🔥' })); // Fire
|
|
373
|
-
app.use(emojiFavicon({ icon: '⚡' })); // Lightning
|
|
374
|
-
app.use(emojiFavicon({ icon: '🎯' })); // Target
|
|
375
|
-
app.use(emojiFavicon({ icon: '🌟' })); // Star
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
:::tip Browser Support
|
|
379
|
-
SVG favicons are supported in all modern browsers. Fallback to a traditional `.ico` file if you need to support legacy browsers.
|
|
380
|
-
:::
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
## Creating Custom Middleware
|
|
384
|
-
|
|
385
|
-
IGNIS uses Hono's middleware system. Create custom middleware using the `createMiddleware` factory:
|
|
386
|
-
|
|
387
|
-
### Basic Middleware
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
import { createMiddleware } from 'hono/factory';
|
|
391
|
-
import type { MiddlewareHandler } from 'hono';
|
|
392
|
-
|
|
393
|
-
export const myMiddleware = (): MiddlewareHandler => {
|
|
394
|
-
return createMiddleware(async (context, next) => {
|
|
395
|
-
// Before request handling
|
|
396
|
-
console.log('Before:', context.req.path);
|
|
397
|
-
|
|
398
|
-
await next();
|
|
399
|
-
|
|
400
|
-
// After request handling
|
|
401
|
-
console.log('After:', context.req.path);
|
|
402
|
-
});
|
|
403
|
-
};
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
### Middleware with Options
|
|
407
|
-
|
|
408
|
-
```typescript
|
|
409
|
-
interface MyMiddlewareOptions {
|
|
410
|
-
enabled: boolean;
|
|
411
|
-
prefix?: string;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
export const myMiddleware = (opts: MyMiddlewareOptions): MiddlewareHandler => {
|
|
415
|
-
const { enabled, prefix = 'LOG' } = opts;
|
|
416
|
-
|
|
417
|
-
return createMiddleware(async (context, next) => {
|
|
418
|
-
if (enabled) {
|
|
419
|
-
console.log(`[${prefix}]`, context.req.path);
|
|
420
|
-
}
|
|
421
|
-
await next();
|
|
422
|
-
});
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
// Usage
|
|
426
|
-
app.use(myMiddleware({ enabled: true, prefix: 'API' }));
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### Provider-Based Middleware
|
|
430
|
-
|
|
431
|
-
For middleware requiring dependency injection:
|
|
432
|
-
|
|
433
|
-
```typescript
|
|
434
|
-
import { BaseHelper } from '@venizia/ignis-helpers';
|
|
435
|
-
import { IProvider } from '@venizia/ignis-inversion';
|
|
436
|
-
import { injectable } from '@venizia/ignis-inversion';
|
|
437
|
-
import { createMiddleware } from 'hono/factory';
|
|
438
|
-
import type { MiddlewareHandler } from 'hono';
|
|
439
|
-
|
|
440
|
-
@injectable()
|
|
441
|
-
export class MyMiddleware extends BaseHelper implements IProvider<MiddlewareHandler> {
|
|
442
|
-
constructor() {
|
|
443
|
-
super({ scope: MyMiddleware.name });
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
value(): MiddlewareHandler {
|
|
447
|
-
return createMiddleware(async (context, next) => {
|
|
448
|
-
this.logger.info('Processing request:', context.req.path);
|
|
449
|
-
await next();
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Usage
|
|
455
|
-
const myMiddleware = app.get(MyMiddleware);
|
|
456
|
-
app.use(myMiddleware.value());
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
## Middleware Order & Priority
|
|
461
|
-
|
|
462
|
-
Middleware execution order matters. Follow these guidelines:
|
|
463
|
-
|
|
464
|
-
### Recommended Order
|
|
465
|
-
|
|
466
|
-
```typescript
|
|
467
|
-
const app = new IgnisApplication({ /* ... */ });
|
|
468
|
-
|
|
469
|
-
// 1. CORS (if needed)
|
|
470
|
-
app.use(cors());
|
|
471
|
-
|
|
472
|
-
// 2. Request ID generation
|
|
473
|
-
app.use(requestId());
|
|
474
|
-
|
|
475
|
-
// 3. Request spy/logging (also handles body parsing)
|
|
476
|
-
const requestSpy = new RequestSpyMiddleware();
|
|
477
|
-
app.use(requestSpy.value());
|
|
478
|
-
|
|
479
|
-
// 4. Security middleware (helmet, etc.)
|
|
480
|
-
app.use(helmet());
|
|
481
|
-
|
|
482
|
-
// 5. Rate limiting
|
|
483
|
-
app.use(rateLimit());
|
|
484
|
-
|
|
485
|
-
// 6. Authentication
|
|
486
|
-
app.use('/api/*', authenticate());
|
|
487
|
-
|
|
488
|
-
// 7. Favicon (can be early or late)
|
|
489
|
-
app.use(emojiFavicon({ icon: '🚀' }));
|
|
490
|
-
|
|
491
|
-
// 8. Application routes
|
|
492
|
-
app.mountControllers();
|
|
493
|
-
|
|
494
|
-
// 9. Error handler (LAST in chain)
|
|
495
|
-
app.onError(appErrorHandler({ logger: app.logger }));
|
|
496
|
-
|
|
497
|
-
// 10. Not found handler (AFTER error handler)
|
|
498
|
-
app.notFound(notFoundHandler({ logger: app.logger }));
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
### Key Principles
|
|
502
|
-
|
|
503
|
-
1. **Request ID First**: Generate request ID before logging
|
|
504
|
-
2. **Request Spy Early**: Log and parse request bodies before business logic
|
|
505
|
-
3. **Security Middleware Before Routes**: Protect routes with security checks
|
|
506
|
-
4. **Error Handler Last**: Catch all errors from previous middleware
|
|
507
|
-
5. **404 Handler After Error Handler**: Ensure unhandled routes return 404
|
|
508
|
-
|
|
509
|
-
:::warning Order Matters
|
|
510
|
-
Placing error handler before routes will prevent it from catching route errors. Always register error handlers last.
|
|
511
|
-
:::
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
## Common Patterns
|
|
515
|
-
|
|
516
|
-
### Conditional Middleware
|
|
517
|
-
|
|
518
|
-
```typescript
|
|
519
|
-
const app = new IgnisApplication({ /* ... */ });
|
|
520
|
-
|
|
521
|
-
// Enable request spy only in development
|
|
522
|
-
if (process.env.NODE_ENV === 'development') {
|
|
523
|
-
const requestSpy = new RequestSpyMiddleware();
|
|
524
|
-
app.use(requestSpy.value());
|
|
525
|
-
}
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
### Route-Specific Middleware
|
|
529
|
-
|
|
530
|
-
```typescript
|
|
531
|
-
// Apply middleware to specific routes
|
|
532
|
-
app.use('/api/admin/*', adminAuthMiddleware());
|
|
533
|
-
app.use('/api/public/*', rateLimitMiddleware());
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
### Middleware Composition
|
|
537
|
-
|
|
538
|
-
```typescript
|
|
539
|
-
// Combine multiple middleware
|
|
540
|
-
const apiMiddleware = (): MiddlewareHandler => {
|
|
541
|
-
return createMiddleware(async (context, next) => {
|
|
542
|
-
// Run multiple middleware in sequence
|
|
543
|
-
await rateLimit()(context, async () => {
|
|
544
|
-
await authenticate()(context, next);
|
|
545
|
-
});
|
|
546
|
-
});
|
|
547
|
-
};
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
## Performance Considerations
|
|
552
|
-
|
|
553
|
-
### Request Spy in Production
|
|
554
|
-
|
|
555
|
-
Request spy logs detailed information for every request. In high-traffic production environments:
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
// Conditional request spy
|
|
559
|
-
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
560
|
-
|
|
561
|
-
if (isDevelopment) {
|
|
562
|
-
const requestSpy = new RequestSpyMiddleware();
|
|
563
|
-
app.use(requestSpy.value());
|
|
564
|
-
}
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
### Error Logging Volume
|
|
568
|
-
|
|
569
|
-
Error handlers log every error. For high error rates, consider:
|
|
570
|
-
- Sampling (log 1 in N errors)
|
|
571
|
-
- Error aggregation services (Sentry, Rollbar)
|
|
572
|
-
- Rate-limited logging
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
## See Also
|
|
576
|
-
|
|
577
|
-
- **Related References:**
|
|
578
|
-
- [Application](./application.md) - Application setup and configuration
|
|
579
|
-
- [Controllers](./controllers.md) - HTTP routing and request handling
|
|
580
|
-
- [Dependency Injection](./dependency-injection.md) - DI container and providers
|
|
581
|
-
|
|
582
|
-
- **Guides:**
|
|
583
|
-
- [Building a CRUD API](/guides/tutorials/building-a-crud-api)
|
|
584
|
-
|
|
585
|
-
- **Best Practices:**
|
|
586
|
-
- [Troubleshooting Tips](/best-practices/troubleshooting-tips)
|
|
587
|
-
|
|
588
|
-
- **External Resources:**
|
|
589
|
-
- [Hono Middleware Documentation](https://hono.dev/docs/guides/middleware)
|
|
590
|
-
- [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
|