@engjts/nexus 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/BENCHMARK_REPORT.md +0 -343
- package/documentation/01-getting-started.md +0 -240
- package/documentation/02-context.md +0 -335
- package/documentation/03-routing.md +0 -397
- package/documentation/04-middleware.md +0 -483
- package/documentation/05-validation.md +0 -514
- package/documentation/06-error-handling.md +0 -465
- package/documentation/07-performance.md +0 -364
- package/documentation/08-adapters.md +0 -470
- package/documentation/09-api-reference.md +0 -548
- package/documentation/10-examples.md +0 -582
- package/documentation/11-deployment.md +0 -477
- package/documentation/12-sentry.md +0 -620
- package/documentation/13-sentry-data-storage.md +0 -996
- package/documentation/14-sentry-data-reference.md +0 -457
- package/documentation/15-sentry-summary.md +0 -409
- package/documentation/16-alerts-system.md +0 -745
- package/documentation/17-alert-adapters.md +0 -696
- package/documentation/18-alerts-implementation-summary.md +0 -385
- package/documentation/19-class-based-routing.md +0 -840
- package/documentation/20-websocket-realtime.md +0 -813
- package/documentation/21-cache-system.md +0 -510
- package/documentation/22-job-queue.md +0 -772
- package/documentation/23-sentry-plugin.md +0 -551
- package/documentation/24-testing-utilities.md +0 -1287
- package/documentation/25-api-versioning.md +0 -533
- package/documentation/26-context-store.md +0 -607
- package/documentation/27-dependency-injection.md +0 -329
- package/documentation/28-lifecycle-hooks.md +0 -521
- package/documentation/29-package-structure.md +0 -196
- package/documentation/30-plugin-system.md +0 -414
- package/documentation/31-jwt-authentication.md +0 -597
- package/documentation/32-cli.md +0 -268
- package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
- package/documentation/ALERTS-INDEX.md +0 -330
- package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
- package/documentation/README.md +0 -178
- package/documentation/index.html +0 -34
- package/modern_framework_paper.md +0 -1870
- package/public/css/style.css +0 -87
- package/public/index.html +0 -34
- package/public/js/app.js +0 -27
- package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
- package/src/advanced/cache/MultiTierCache.ts +0 -194
- package/src/advanced/cache/RedisCacheStore.ts +0 -341
- package/src/advanced/cache/index.ts +0 -5
- package/src/advanced/cache/types.ts +0 -40
- package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
- package/src/advanced/graphql/index.ts +0 -22
- package/src/advanced/graphql/server.ts +0 -252
- package/src/advanced/graphql/types.ts +0 -42
- package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
- package/src/advanced/jobs/JobQueue.ts +0 -556
- package/src/advanced/jobs/RedisQueueStore.ts +0 -367
- package/src/advanced/jobs/index.ts +0 -5
- package/src/advanced/jobs/types.ts +0 -70
- package/src/advanced/observability/APMManager.ts +0 -163
- package/src/advanced/observability/AlertManager.ts +0 -109
- package/src/advanced/observability/MetricRegistry.ts +0 -151
- package/src/advanced/observability/ObservabilityCenter.ts +0 -304
- package/src/advanced/observability/StructuredLogger.ts +0 -154
- package/src/advanced/observability/TracingManager.ts +0 -117
- package/src/advanced/observability/adapters.ts +0 -304
- package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
- package/src/advanced/observability/index.ts +0 -11
- package/src/advanced/observability/types.ts +0 -174
- package/src/advanced/playground/extractPathParams.ts +0 -6
- package/src/advanced/playground/generateFieldExample.ts +0 -31
- package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
- package/src/advanced/playground/generateSummary.ts +0 -19
- package/src/advanced/playground/getTagFromPath.ts +0 -9
- package/src/advanced/playground/index.ts +0 -8
- package/src/advanced/playground/playground.ts +0 -250
- package/src/advanced/playground/types.ts +0 -49
- package/src/advanced/playground/zodToExample.ts +0 -16
- package/src/advanced/playground/zodToParams.ts +0 -15
- package/src/advanced/postman/buildAuth.ts +0 -31
- package/src/advanced/postman/buildBody.ts +0 -15
- package/src/advanced/postman/buildQueryParams.ts +0 -27
- package/src/advanced/postman/buildRequestItem.ts +0 -36
- package/src/advanced/postman/buildResponses.ts +0 -11
- package/src/advanced/postman/buildUrl.ts +0 -33
- package/src/advanced/postman/capitalize.ts +0 -4
- package/src/advanced/postman/generateCollection.ts +0 -59
- package/src/advanced/postman/generateEnvironment.ts +0 -34
- package/src/advanced/postman/generateExampleFromZod.ts +0 -21
- package/src/advanced/postman/generateFieldExample.ts +0 -45
- package/src/advanced/postman/generateName.ts +0 -20
- package/src/advanced/postman/generateUUID.ts +0 -11
- package/src/advanced/postman/getTagFromPath.ts +0 -10
- package/src/advanced/postman/index.ts +0 -28
- package/src/advanced/postman/postman.ts +0 -156
- package/src/advanced/postman/slugify.ts +0 -7
- package/src/advanced/postman/types.ts +0 -140
- package/src/advanced/realtime/index.ts +0 -18
- package/src/advanced/realtime/websocket.ts +0 -231
- package/src/advanced/sentry/index.ts +0 -1236
- package/src/advanced/sentry/types.ts +0 -355
- package/src/advanced/static/generateDirectoryListing.ts +0 -47
- package/src/advanced/static/generateETag.ts +0 -7
- package/src/advanced/static/getMimeType.ts +0 -9
- package/src/advanced/static/index.ts +0 -32
- package/src/advanced/static/isSafePath.ts +0 -13
- package/src/advanced/static/publicDir.ts +0 -21
- package/src/advanced/static/serveStatic.ts +0 -225
- package/src/advanced/static/spa.ts +0 -24
- package/src/advanced/static/types.ts +0 -159
- package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
- package/src/advanced/swagger/buildOperation.ts +0 -61
- package/src/advanced/swagger/buildParameters.ts +0 -61
- package/src/advanced/swagger/buildRequestBody.ts +0 -21
- package/src/advanced/swagger/buildResponses.ts +0 -54
- package/src/advanced/swagger/capitalize.ts +0 -5
- package/src/advanced/swagger/convertPath.ts +0 -9
- package/src/advanced/swagger/createSwagger.ts +0 -12
- package/src/advanced/swagger/generateOperationId.ts +0 -21
- package/src/advanced/swagger/generateSpec.ts +0 -105
- package/src/advanced/swagger/generateSummary.ts +0 -24
- package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
- package/src/advanced/swagger/generateThemeCss.ts +0 -53
- package/src/advanced/swagger/index.ts +0 -25
- package/src/advanced/swagger/swagger.ts +0 -237
- package/src/advanced/swagger/types.ts +0 -206
- package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
- package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
- package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
- package/src/advanced/testing/factory.ts +0 -509
- package/src/advanced/testing/harness.ts +0 -612
- package/src/advanced/testing/index.ts +0 -430
- package/src/advanced/testing/load-test.ts +0 -618
- package/src/advanced/testing/mock-server.ts +0 -498
- package/src/advanced/testing/mock.ts +0 -670
- package/src/cli/bin.ts +0 -9
- package/src/cli/cli.ts +0 -158
- package/src/cli/commands/add.ts +0 -178
- package/src/cli/commands/build.ts +0 -73
- package/src/cli/commands/create.ts +0 -166
- package/src/cli/commands/dev.ts +0 -85
- package/src/cli/commands/generate.ts +0 -99
- package/src/cli/commands/help.ts +0 -95
- package/src/cli/commands/init.ts +0 -91
- package/src/cli/commands/version.ts +0 -38
- package/src/cli/index.ts +0 -6
- package/src/cli/templates/generators.ts +0 -359
- package/src/cli/templates/index.ts +0 -680
- package/src/cli/utils/exec.ts +0 -52
- package/src/cli/utils/file-system.ts +0 -78
- package/src/cli/utils/logger.ts +0 -111
- package/src/core/adapter.ts +0 -88
- package/src/core/application.ts +0 -1453
- package/src/core/context-pool.ts +0 -79
- package/src/core/context.ts +0 -856
- package/src/core/index.ts +0 -94
- package/src/core/middleware.ts +0 -272
- package/src/core/performance/buffer-pool.ts +0 -108
- package/src/core/performance/middleware-optimizer.ts +0 -162
- package/src/core/plugin/PluginManager.ts +0 -435
- package/src/core/plugin/builder.ts +0 -358
- package/src/core/plugin/index.ts +0 -50
- package/src/core/plugin/types.ts +0 -214
- package/src/core/router/file-router.ts +0 -623
- package/src/core/router/index.ts +0 -260
- package/src/core/router/radix-tree.ts +0 -242
- package/src/core/serializer.ts +0 -397
- package/src/core/store/index.ts +0 -30
- package/src/core/store/registry.ts +0 -178
- package/src/core/store/request-store.ts +0 -240
- package/src/core/store/types.ts +0 -233
- package/src/core/types.ts +0 -616
- package/src/database/adapter.ts +0 -35
- package/src/database/adapters/index.ts +0 -1
- package/src/database/adapters/mysql.ts +0 -669
- package/src/database/database.ts +0 -70
- package/src/database/dialect.ts +0 -388
- package/src/database/index.ts +0 -12
- package/src/database/migrations.ts +0 -86
- package/src/database/optimizer.ts +0 -125
- package/src/database/query-builder.ts +0 -404
- package/src/database/realtime.ts +0 -53
- package/src/database/schema.ts +0 -71
- package/src/database/transactions.ts +0 -56
- package/src/database/types.ts +0 -87
- package/src/deployment/cluster.ts +0 -471
- package/src/deployment/config.ts +0 -454
- package/src/deployment/docker.ts +0 -599
- package/src/deployment/graceful-shutdown.ts +0 -373
- package/src/deployment/index.ts +0 -56
- package/src/index.ts +0 -281
- package/src/security/adapter.ts +0 -318
- package/src/security/auth/JWTPlugin.ts +0 -234
- package/src/security/auth/JWTProvider.ts +0 -316
- package/src/security/auth/adapter.ts +0 -12
- package/src/security/auth/jwt.ts +0 -234
- package/src/security/auth/middleware.ts +0 -188
- package/src/security/csrf.ts +0 -220
- package/src/security/headers.ts +0 -108
- package/src/security/index.ts +0 -60
- package/src/security/rate-limit/adapter.ts +0 -7
- package/src/security/rate-limit/memory.ts +0 -108
- package/src/security/rate-limit/middleware.ts +0 -181
- package/src/security/sanitization.ts +0 -75
- package/src/security/types.ts +0 -240
- package/src/security/utils.ts +0 -52
- package/tsconfig.json +0 -39
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
# Context API
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The **Context** is the heart of Nexus Framework. It replaces the traditional `req` and `res` pattern with a single, unified, immutable object that contains all request and response data.
|
|
6
|
-
|
|
7
|
-
## Why Context?
|
|
8
|
-
|
|
9
|
-
### Traditional Express.js
|
|
10
|
-
```javascript
|
|
11
|
-
app.get('/user/:id', (req, res) => {
|
|
12
|
-
const id = req.params.id;
|
|
13
|
-
const user = getUser(id);
|
|
14
|
-
res.json({ user });
|
|
15
|
-
});
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### Nexus Framework
|
|
19
|
-
```typescript
|
|
20
|
-
app.get('/user/:id', async (ctx) => {
|
|
21
|
-
const user = await getUser(ctx.params.id);
|
|
22
|
-
return { user }; // Auto-converted to JSON
|
|
23
|
-
});
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**Benefits:**
|
|
27
|
-
- ✅ Single source of truth
|
|
28
|
-
- ✅ Immutability enables better testing
|
|
29
|
-
- ✅ Type inference works naturally
|
|
30
|
-
- ✅ Easier to extend with custom properties
|
|
31
|
-
|
|
32
|
-
## Context Properties
|
|
33
|
-
|
|
34
|
-
### Request Data
|
|
35
|
-
|
|
36
|
-
#### `ctx.method`
|
|
37
|
-
HTTP method of the request.
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
app.get('/info', async (ctx) => {
|
|
41
|
-
return { method: ctx.method }; // "GET"
|
|
42
|
-
});
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
#### `ctx.path`
|
|
46
|
-
Path of the request (without query string).
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
app.get('/api/users', async (ctx) => {
|
|
50
|
-
return { path: ctx.path }; // "/api/users"
|
|
51
|
-
});
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
#### `ctx.url`
|
|
55
|
-
Full URL object.
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
app.get('/info', async (ctx) => {
|
|
59
|
-
return {
|
|
60
|
-
host: ctx.url.host,
|
|
61
|
-
protocol: ctx.url.protocol
|
|
62
|
-
};
|
|
63
|
-
});
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
#### `ctx.params`
|
|
67
|
-
Route parameters extracted from the path.
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
app.get('/users/:id/posts/:postId', async (ctx) => {
|
|
71
|
-
const { id, postId } = ctx.params;
|
|
72
|
-
return { userId: id, postId };
|
|
73
|
-
});
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
#### `ctx.query`
|
|
77
|
-
Query string parameters.
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
// GET /search?q=nexus&limit=10
|
|
81
|
-
app.get('/search', async (ctx) => {
|
|
82
|
-
const { q, limit } = ctx.query;
|
|
83
|
-
return { query: q, limit: parseInt(limit) };
|
|
84
|
-
});
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
#### `ctx.body`
|
|
88
|
-
Parsed request body (POST, PUT, PATCH).
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
app.post('/users', async (ctx) => {
|
|
92
|
-
const { name, email } = ctx.body;
|
|
93
|
-
return { received: { name, email } };
|
|
94
|
-
});
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Automatic parsing for:**
|
|
98
|
-
- `application/json`
|
|
99
|
-
- `application/x-www-form-urlencoded`
|
|
100
|
-
- `text/*`
|
|
101
|
-
|
|
102
|
-
#### `ctx.headers`
|
|
103
|
-
Request headers.
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
app.get('/auth', async (ctx) => {
|
|
107
|
-
const token = ctx.headers.authorization;
|
|
108
|
-
const userAgent = ctx.headers['user-agent'];
|
|
109
|
-
return { token, userAgent };
|
|
110
|
-
});
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
#### `ctx.cookies`
|
|
114
|
-
Cookie management.
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
app.get('/profile', async (ctx) => {
|
|
118
|
-
// Get cookie
|
|
119
|
-
const sessionId = ctx.cookies.get('session');
|
|
120
|
-
|
|
121
|
-
// Set cookie
|
|
122
|
-
ctx.cookies.set('visited', 'true', {
|
|
123
|
-
maxAge: 86400, // 1 day in seconds
|
|
124
|
-
httpOnly: true,
|
|
125
|
-
secure: true,
|
|
126
|
-
sameSite: 'strict'
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Delete cookie
|
|
130
|
-
ctx.cookies.delete('old-cookie');
|
|
131
|
-
|
|
132
|
-
return { sessionId };
|
|
133
|
-
});
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Response Methods
|
|
137
|
-
|
|
138
|
-
### `ctx.json(data)`
|
|
139
|
-
Return JSON response.
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
app.get('/user', async (ctx) => {
|
|
143
|
-
return ctx.json({
|
|
144
|
-
name: 'John',
|
|
145
|
-
email: 'john@example.com'
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Or simply return the object (auto-converted)
|
|
150
|
-
app.get('/user', async (ctx) => {
|
|
151
|
-
return { name: 'John', email: 'john@example.com' };
|
|
152
|
-
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### `ctx.html(content)`
|
|
156
|
-
Return HTML response.
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
app.get('/page', async (ctx) => {
|
|
160
|
-
return ctx.html(`
|
|
161
|
-
<!DOCTYPE html>
|
|
162
|
-
<html>
|
|
163
|
-
<head><title>My Page</title></head>
|
|
164
|
-
<body><h1>Welcome!</h1></body>
|
|
165
|
-
</html>
|
|
166
|
-
`);
|
|
167
|
-
});
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### `ctx.text(content)`
|
|
171
|
-
Return plain text response.
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
app.get('/robots.txt', async (ctx) => {
|
|
175
|
-
return ctx.text('User-agent: *\nDisallow: /admin/');
|
|
176
|
-
});
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### `ctx.redirect(url, status?)`
|
|
180
|
-
Redirect to another URL.
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
app.get('/old-page', async (ctx) => {
|
|
184
|
-
return ctx.redirect('/new-page', 301); // Permanent redirect
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
app.get('/login', async (ctx) => {
|
|
188
|
-
return ctx.redirect('/auth/login'); // Default 302
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### `ctx.stream(readable)`
|
|
193
|
-
Stream a response (for large files).
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
import { createReadStream } from 'fs';
|
|
197
|
-
|
|
198
|
-
app.get('/download', async (ctx) => {
|
|
199
|
-
const stream = createReadStream('./large-file.zip');
|
|
200
|
-
return ctx.stream(stream);
|
|
201
|
-
});
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
## Response Builder
|
|
205
|
-
|
|
206
|
-
Use the response builder for custom status codes and headers:
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
app.get('/custom', async (ctx) => {
|
|
210
|
-
return ctx.response
|
|
211
|
-
.status(201)
|
|
212
|
-
.header('X-Custom-Header', 'value')
|
|
213
|
-
.json({ created: true });
|
|
214
|
-
});
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## Raw Node.js Objects
|
|
218
|
-
|
|
219
|
-
Access raw Node.js objects when needed:
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
app.get('/raw', async (ctx) => {
|
|
223
|
-
// Access raw request
|
|
224
|
-
const req = ctx.raw.req;
|
|
225
|
-
const contentLength = req.headers['content-length'];
|
|
226
|
-
|
|
227
|
-
// Access raw response
|
|
228
|
-
const res = ctx.raw.res;
|
|
229
|
-
res.setHeader('X-Custom', 'value');
|
|
230
|
-
|
|
231
|
-
return { contentLength };
|
|
232
|
-
});
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
## Custom Context Properties
|
|
236
|
-
|
|
237
|
-
Middleware can add custom properties to the context:
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
// Middleware adds user
|
|
241
|
-
const auth = async (ctx: any, next: any) => {
|
|
242
|
-
ctx.user = await authenticateUser(ctx.headers.authorization);
|
|
243
|
-
return next(ctx);
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
app.get('/profile', {
|
|
247
|
-
middlewares: [auth],
|
|
248
|
-
handler: async (ctx: any) => {
|
|
249
|
-
// ctx.user is now available
|
|
250
|
-
return { user: ctx.user };
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
For type-safe custom properties, see [Middleware Documentation](./04-middleware.md).
|
|
256
|
-
|
|
257
|
-
## Context Pooling
|
|
258
|
-
|
|
259
|
-
Nexus automatically pools context objects for performance. You don't need to do anything - it's built-in!
|
|
260
|
-
|
|
261
|
-
**Performance benefit:** ~60-80% reduction in object allocations.
|
|
262
|
-
|
|
263
|
-
```typescript
|
|
264
|
-
// Get pool statistics
|
|
265
|
-
const app = createApp();
|
|
266
|
-
// ... after some requests
|
|
267
|
-
const stats = app.getPoolStats();
|
|
268
|
-
console.log(stats);
|
|
269
|
-
// {
|
|
270
|
-
// poolSize: 50,
|
|
271
|
-
// maxSize: 100,
|
|
272
|
-
// created: 150,
|
|
273
|
-
// reused: 100,
|
|
274
|
-
// hitRate: 0.67
|
|
275
|
-
// }
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
## Best Practices
|
|
279
|
-
|
|
280
|
-
### ✅ DO: Return data directly
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
app.get('/users', async (ctx) => {
|
|
284
|
-
const users = await getUsers();
|
|
285
|
-
return { users };
|
|
286
|
-
});
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### ❌ DON'T: Mutate the context
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
// BAD - context is immutable
|
|
293
|
-
app.get('/bad', async (ctx) => {
|
|
294
|
-
ctx.path = '/new-path'; // Won't work!
|
|
295
|
-
});
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### ✅ DO: Use typed custom properties
|
|
299
|
-
|
|
300
|
-
```typescript
|
|
301
|
-
interface AuthContext extends Context {
|
|
302
|
-
user: User;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const handler = async (ctx: AuthContext) => {
|
|
306
|
-
return { userId: ctx.user.id }; // Type-safe!
|
|
307
|
-
};
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### ✅ DO: Use cookies for session management
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
app.post('/login', async (ctx) => {
|
|
314
|
-
const user = await authenticate(ctx.body);
|
|
315
|
-
|
|
316
|
-
ctx.cookies.set('session', user.sessionId, {
|
|
317
|
-
httpOnly: true,
|
|
318
|
-
secure: true,
|
|
319
|
-
sameSite: 'strict',
|
|
320
|
-
maxAge: 86400
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
return { success: true };
|
|
324
|
-
});
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
## Next Steps
|
|
328
|
-
|
|
329
|
-
- 🛤️ [Routing Guide](./03-routing.md) - Learn about routing
|
|
330
|
-
- 🔌 [Middleware](./04-middleware.md) - Extend context with middleware
|
|
331
|
-
- ✅ [Validation](./05-validation.md) - Validate context data
|
|
332
|
-
|
|
333
|
-
---
|
|
334
|
-
|
|
335
|
-
[← Getting Started](./01-getting-started.md) | [API Reference →](./09-api-reference.md)
|
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
# Routing Guide
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Nexus uses a **Radix Tree** for routing, providing O(log n) lookup performance. The routing system supports static routes, dynamic parameters, and wildcards.
|
|
6
|
-
|
|
7
|
-
## Basic Routes
|
|
8
|
-
|
|
9
|
-
### Static Routes
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
app.get('/about', async (ctx) => {
|
|
13
|
-
return { page: 'about' };
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
app.get('/api/users', async (ctx) => {
|
|
17
|
-
return { users: [] };
|
|
18
|
-
});
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### HTTP Methods
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
app.get('/resource', async (ctx) => {
|
|
25
|
-
return { method: 'GET' };
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
app.post('/resource', async (ctx) => {
|
|
29
|
-
return { method: 'POST', body: ctx.body };
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
app.put('/resource/:id', async (ctx) => {
|
|
33
|
-
return { method: 'PUT', id: ctx.params.id };
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
app.patch('/resource/:id', async (ctx) => {
|
|
37
|
-
return { method: 'PATCH', id: ctx.params.id };
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
app.delete('/resource/:id', async (ctx) => {
|
|
41
|
-
return { method: 'DELETE', id: ctx.params.id };
|
|
42
|
-
});
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Dynamic Routes
|
|
46
|
-
|
|
47
|
-
### Single Parameter
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
app.get('/users/:id', async (ctx) => {
|
|
51
|
-
const userId = ctx.params.id;
|
|
52
|
-
const user = await getUser(userId);
|
|
53
|
-
return { user };
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Multiple Parameters
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
app.get('/users/:userId/posts/:postId', async (ctx) => {
|
|
61
|
-
const { userId, postId } = ctx.params;
|
|
62
|
-
const post = await getPost(userId, postId);
|
|
63
|
-
return { post };
|
|
64
|
-
});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Parameter Naming
|
|
68
|
-
|
|
69
|
-
Use descriptive parameter names:
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// Good
|
|
73
|
-
app.get('/articles/:articleId/comments/:commentId', ...);
|
|
74
|
-
|
|
75
|
-
// Avoid
|
|
76
|
-
app.get('/articles/:id1/comments/:id2', ...);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Wildcard Routes
|
|
80
|
-
|
|
81
|
-
Capture the remaining path with `*`:
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
app.get('/files/*filepath', async (ctx) => {
|
|
85
|
-
const filepath = ctx.params.filepath;
|
|
86
|
-
// filepath = "docs/guide/intro.md" for /files/docs/guide/intro.md
|
|
87
|
-
return { filepath };
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
app.get('/proxy/*', async (ctx) => {
|
|
91
|
-
const path = ctx.params.wildcard; // default name
|
|
92
|
-
return { proxiedPath: path };
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Route Priority
|
|
97
|
-
|
|
98
|
-
Routes are matched in this order:
|
|
99
|
-
|
|
100
|
-
1. **Static** - Exact matches
|
|
101
|
-
2. **Parameters** - Dynamic segments (`:param`)
|
|
102
|
-
3. **Wildcards** - Catch-all (`*`)
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
app.get('/users/active', ...); // 1. Matched first
|
|
106
|
-
app.get('/users/:id', ...); // 2. Matched second
|
|
107
|
-
app.get('/users/*', ...); // 3. Matched last
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Example:
|
|
111
|
-
- `/users/active` → matches static route
|
|
112
|
-
- `/users/123` → matches parameter route
|
|
113
|
-
- `/users/admin/settings` → matches wildcard route
|
|
114
|
-
|
|
115
|
-
## Declarative Route Definition
|
|
116
|
-
|
|
117
|
-
Use the `route()` method for advanced configuration:
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
import { z } from 'zod';
|
|
121
|
-
|
|
122
|
-
app.route({
|
|
123
|
-
method: 'POST',
|
|
124
|
-
path: '/api/users',
|
|
125
|
-
|
|
126
|
-
// Schema validation
|
|
127
|
-
schema: {
|
|
128
|
-
body: z.object({
|
|
129
|
-
name: z.string().min(2),
|
|
130
|
-
email: z.string().email()
|
|
131
|
-
})
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
// Middleware
|
|
135
|
-
middlewares: [authenticate, rateLimit],
|
|
136
|
-
|
|
137
|
-
// Handler
|
|
138
|
-
handler: async (ctx) => {
|
|
139
|
-
const user = await createUser(ctx.body);
|
|
140
|
-
return { user };
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
// Metadata (for documentation)
|
|
144
|
-
meta: {
|
|
145
|
-
description: 'Create a new user',
|
|
146
|
-
tags: ['users'],
|
|
147
|
-
responses: {
|
|
148
|
-
201: 'User created',
|
|
149
|
-
400: 'Validation error'
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Route Groups
|
|
156
|
-
|
|
157
|
-
Organize routes by creating separate router modules:
|
|
158
|
-
|
|
159
|
-
### `routes/users.ts`
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import { Router } from '../nexus';
|
|
163
|
-
|
|
164
|
-
export const userRoutes = (app: Application) => {
|
|
165
|
-
app.get('/users', async (ctx) => {
|
|
166
|
-
return { users: await getUsers() };
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
app.get('/users/:id', async (ctx) => {
|
|
170
|
-
return { user: await getUser(ctx.params.id) };
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
app.post('/users', {
|
|
174
|
-
schema: { /* ... */ },
|
|
175
|
-
handler: async (ctx) => { /* ... */ }
|
|
176
|
-
});
|
|
177
|
-
};
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### `index.ts`
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
import { createApp } from './nexus';
|
|
184
|
-
import { userRoutes } from './routes/users';
|
|
185
|
-
import { postRoutes } from './routes/posts';
|
|
186
|
-
|
|
187
|
-
const app = createApp();
|
|
188
|
-
|
|
189
|
-
userRoutes(app);
|
|
190
|
-
postRoutes(app);
|
|
191
|
-
|
|
192
|
-
app.listen(3000);
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## Route Prefixes
|
|
196
|
-
|
|
197
|
-
Create prefixed route groups:
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
const createAPIRoutes = (app: Application, prefix: string) => {
|
|
201
|
-
app.get(`${prefix}/users`, ...);
|
|
202
|
-
app.get(`${prefix}/posts`, ...);
|
|
203
|
-
app.get(`${prefix}/comments`, ...);
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
createAPIRoutes(app, '/api/v1');
|
|
207
|
-
createAPIRoutes(app, '/api/v2');
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Query Parameters
|
|
211
|
-
|
|
212
|
-
Access query parameters via `ctx.query`:
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
// GET /search?q=nexus&page=2&limit=20
|
|
216
|
-
app.get('/search', async (ctx) => {
|
|
217
|
-
const query = ctx.query.q;
|
|
218
|
-
const page = parseInt(ctx.query.page) || 1;
|
|
219
|
-
const limit = parseInt(ctx.query.limit) || 10;
|
|
220
|
-
|
|
221
|
-
const results = await search(query, page, limit);
|
|
222
|
-
return { results, page, limit };
|
|
223
|
-
});
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Type-Safe Query Validation
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
import { z } from 'zod';
|
|
230
|
-
|
|
231
|
-
app.get('/search', {
|
|
232
|
-
schema: {
|
|
233
|
-
query: z.object({
|
|
234
|
-
q: z.string().min(1),
|
|
235
|
-
page: z.string().regex(/^\d+$/).transform(Number).default('1'),
|
|
236
|
-
limit: z.string().regex(/^\d+$/).transform(Number).default('10')
|
|
237
|
-
})
|
|
238
|
-
},
|
|
239
|
-
handler: async (ctx) => {
|
|
240
|
-
// ctx.query is now typed and validated
|
|
241
|
-
const { q, page, limit } = ctx.query;
|
|
242
|
-
return await search(q, page, limit);
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## 404 Not Found
|
|
248
|
-
|
|
249
|
-
Nexus automatically returns 404 for unmatched routes:
|
|
250
|
-
|
|
251
|
-
```json
|
|
252
|
-
{
|
|
253
|
-
"error": "Not Found"
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
Custom 404 handler:
|
|
258
|
-
|
|
259
|
-
```typescript
|
|
260
|
-
// Add a wildcard route at the end
|
|
261
|
-
app.get('/*', async (ctx) => {
|
|
262
|
-
return ctx.response.status(404).json({
|
|
263
|
-
error: 'Page not found',
|
|
264
|
-
path: ctx.path
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
## Route Introspection
|
|
270
|
-
|
|
271
|
-
Get all registered routes:
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
const routes = app.getRoutes();
|
|
275
|
-
console.log(routes);
|
|
276
|
-
// [
|
|
277
|
-
// { method: 'GET', path: '/users' },
|
|
278
|
-
// { method: 'GET', path: '/users/:id' },
|
|
279
|
-
// { method: 'POST', path: '/users' }
|
|
280
|
-
// ]
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Useful for:
|
|
284
|
-
- Generating API documentation
|
|
285
|
-
- Debugging route conflicts
|
|
286
|
-
- Creating route lists
|
|
287
|
-
|
|
288
|
-
## Best Practices
|
|
289
|
-
|
|
290
|
-
### ✅ DO: Use RESTful conventions
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
app.get('/users', ...); // List users
|
|
294
|
-
app.get('/users/:id', ...); // Get user
|
|
295
|
-
app.post('/users', ...); // Create user
|
|
296
|
-
app.put('/users/:id', ...); // Update user (full)
|
|
297
|
-
app.patch('/users/:id', ...); // Update user (partial)
|
|
298
|
-
app.delete('/users/:id', ...); // Delete user
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### ✅ DO: Version your API
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
app.get('/api/v1/users', ...);
|
|
305
|
-
app.get('/api/v2/users', ...);
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### ✅ DO: Use specific routes before wildcards
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
// Correct order
|
|
312
|
-
app.get('/admin/dashboard', ...);
|
|
313
|
-
app.get('/admin/*', ...);
|
|
314
|
-
|
|
315
|
-
// Wrong order - dashboard will never be reached
|
|
316
|
-
app.get('/admin/*', ...);
|
|
317
|
-
app.get('/admin/dashboard', ...);
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### ❌ DON'T: Create ambiguous routes
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
// Ambiguous - which route matches /users/123?
|
|
324
|
-
app.get('/users/:id', ...);
|
|
325
|
-
app.get('/users/:userId', ...); // Same as above!
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
### ✅ DO: Use consistent naming
|
|
329
|
-
|
|
330
|
-
```typescript
|
|
331
|
-
// Good
|
|
332
|
-
app.get('/users/:userId', ...);
|
|
333
|
-
app.get('/users/:userId/posts/:postId', ...);
|
|
334
|
-
|
|
335
|
-
// Inconsistent
|
|
336
|
-
app.get('/users/:id', ...);
|
|
337
|
-
app.get('/users/:userId/posts/:pid', ...);
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
## Performance
|
|
341
|
-
|
|
342
|
-
### Route Matching
|
|
343
|
-
|
|
344
|
-
Nexus uses a **Radix Tree** for O(log n) route lookup:
|
|
345
|
-
|
|
346
|
-
```typescript
|
|
347
|
-
// Fast - even with 1000+ routes
|
|
348
|
-
app.get('/api/v1/users/:id', ...);
|
|
349
|
-
// Lookup time: ~0.001ms
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### Route Compilation
|
|
353
|
-
|
|
354
|
-
Routes are compiled at startup for optimal performance:
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
const app = createApp({
|
|
358
|
-
enableJIT: true // Enable JIT compilation (default)
|
|
359
|
-
});
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
## Advanced Patterns
|
|
363
|
-
|
|
364
|
-
### Optional Parameters
|
|
365
|
-
|
|
366
|
-
Use query parameters for optional data:
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
// GET /users?role=admin&active=true
|
|
370
|
-
app.get('/users', async (ctx) => {
|
|
371
|
-
const filters = {
|
|
372
|
-
role: ctx.query.role,
|
|
373
|
-
active: ctx.query.active === 'true'
|
|
374
|
-
};
|
|
375
|
-
return await getUsers(filters);
|
|
376
|
-
});
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### File Extensions
|
|
380
|
-
|
|
381
|
-
```typescript
|
|
382
|
-
app.get('/download/:filename', async (ctx) => {
|
|
383
|
-
const filename = ctx.params.filename;
|
|
384
|
-
// filename includes extension: "document.pdf"
|
|
385
|
-
return ctx.stream(createReadStream(filename));
|
|
386
|
-
});
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
## Next Steps
|
|
390
|
-
|
|
391
|
-
- ✅ [Schema Validation](./05-validation.md) - Validate route parameters
|
|
392
|
-
- 🔌 [Middleware](./04-middleware.md) - Add route-specific middleware
|
|
393
|
-
- 🔒 [Error Handling](./06-error-handling.md) - Handle route errors
|
|
394
|
-
|
|
395
|
-
---
|
|
396
|
-
|
|
397
|
-
[← Context API](./02-context.md) | [Middleware →](./04-middleware.md)
|