@rudderjs/router 0.2.0 → 0.2.1
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/boost/guidelines.md +121 -0
- package/package.json +3 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @rudderjs/router
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Decorator-based and fluent HTTP router for RudderJS. Provides a global `router` singleton (alias: `Route`), named routes, URL generation via `route()`, HMAC-signed URLs via `Url`, route-level middleware, and decorator-based controllers (`@Controller`, `@Get`, `@Post`, etc.). The router is a peer of `@rudderjs/core` — core loads it at runtime via `resolveOptionalPeer` to avoid a dependency cycle.
|
|
6
|
+
|
|
7
|
+
## Key Patterns
|
|
8
|
+
|
|
9
|
+
### Fluent routes
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { router, Route } from '@rudderjs/router'
|
|
13
|
+
|
|
14
|
+
Route.get('/api/health', (_req, res) => res.json({ status: 'ok' }))
|
|
15
|
+
Route.post('/api/users', async (req, res) => res.status(201).json(req.body))
|
|
16
|
+
Route.delete('/api/users/:id', handler)
|
|
17
|
+
Route.all('/api/*', (_req, res) => res.status(404).json({ message: 'Not found' })) // any method
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`router` and `Route` are the same global singleton.
|
|
21
|
+
|
|
22
|
+
### Named routes + URL generation
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Route, route } from '@rudderjs/router'
|
|
26
|
+
|
|
27
|
+
Route.get('/users/:id', handler).name('users.show')
|
|
28
|
+
Route.post('/users', handler).name('users.store')
|
|
29
|
+
|
|
30
|
+
route('users.show', { id: 42 }) // '/users/42'
|
|
31
|
+
route('search', { q: 'hi', page: 2 }) // '/search?q=hi&page=2' (unused params → query string)
|
|
32
|
+
route('posts.show', { slug: 'hello' }) // optional ':id?' segment omitted
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Throws if a required parameter is missing or the name is not registered.
|
|
36
|
+
|
|
37
|
+
### Route-level middleware
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
Route.get('/protected', handler, [authMiddleware])
|
|
41
|
+
Route.post('/admin', handler, [authMiddleware, adminMiddleware])
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Decorator controllers
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Controller, Get, Post, Delete, Middleware, router } from '@rudderjs/router'
|
|
48
|
+
|
|
49
|
+
@Controller('/api/users')
|
|
50
|
+
@Middleware([authMiddleware]) // applies to all methods
|
|
51
|
+
class UserController {
|
|
52
|
+
@Get('/')
|
|
53
|
+
index(_req, res) { return res.json({ data: [] }) }
|
|
54
|
+
|
|
55
|
+
@Post('/')
|
|
56
|
+
async create(req, res) { return res.status(201).json({ data: req.body }) }
|
|
57
|
+
|
|
58
|
+
@Delete('/:id')
|
|
59
|
+
@Middleware([adminMiddleware]) // additional middleware on this method only
|
|
60
|
+
async destroy(req, res) { return res.status(204).send('') }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
router.registerController(UserController)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Signed URLs
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { Url } from '@rudderjs/router'
|
|
70
|
+
|
|
71
|
+
Url.signedRoute('invoice.download', { id: 42 })
|
|
72
|
+
// '/invoice/42?signature=abc123...'
|
|
73
|
+
|
|
74
|
+
Url.temporarySignedRoute('invoice.download', 3600, { id: 42 })
|
|
75
|
+
// '/invoice/42?expires=...&signature=...'
|
|
76
|
+
|
|
77
|
+
Url.sign('/some/path?foo=bar') // sign arbitrary path
|
|
78
|
+
Url.isValidSignature(req) // validate on the receiving end
|
|
79
|
+
Url.current(req) // full URL of this request
|
|
80
|
+
Url.previous(req, '/') // Referer header or fallback
|
|
81
|
+
Url.setKey('override-key') // override APP_KEY (e.g. in tests)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The signing key defaults to `APP_KEY`. HMAC-SHA256 with timing-safe comparison.
|
|
85
|
+
|
|
86
|
+
### `ValidateSignature()` middleware
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { ValidateSignature } from '@rudderjs/router'
|
|
90
|
+
|
|
91
|
+
Route.get('/invoice/:id/download', handler, [ValidateSignature()])
|
|
92
|
+
.name('invoice.download')
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Rejects requests with a missing / invalid / expired signature with a `403`.
|
|
96
|
+
|
|
97
|
+
## Common Pitfalls
|
|
98
|
+
|
|
99
|
+
- **Circular dep if you add core to router**: `@rudderjs/core` is a **peer** dependency of router. Never add `@rudderjs/core` to router's `dependencies` or `devDependencies` — core resolves router at runtime via `resolveOptionalPeer('@rudderjs/router')`.
|
|
100
|
+
- **Missing `reflect-metadata`**: decorator controllers require `import 'reflect-metadata'` at the app entry point plus `experimentalDecorators: true` + `emitDecoratorMetadata: true` in tsconfig.
|
|
101
|
+
- **Controller URL must match the view**: if a controller returns `view('dashboard')` but the URL is `/admin/dashboard`, SPA nav falls back to full reloads. Add `export const route = '/admin/dashboard'` in the view file — see `@rudderjs/view`.
|
|
102
|
+
- **`APP_KEY` unset**: `Url.sign*()` throws unless `APP_KEY` is set or `Url.setKey()` is called first.
|
|
103
|
+
- **Named route not found**: `route('foo.bar')` throws if the name wasn't registered. Use `Route.get(...).name('foo.bar')` before the first call.
|
|
104
|
+
- **Double slashes**: composed paths (prefix + route) are normalised automatically — you don't need to strip leading slashes yourself.
|
|
105
|
+
|
|
106
|
+
## Key Imports
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import {
|
|
110
|
+
router, // global singleton
|
|
111
|
+
Route, // alias for router
|
|
112
|
+
route, // URL generator for named routes
|
|
113
|
+
Url, // signed URLs (signedRoute, temporarySignedRoute, isValidSignature, current, previous)
|
|
114
|
+
ValidateSignature,// middleware
|
|
115
|
+
Controller, // decorator: class-level prefix
|
|
116
|
+
Middleware, // decorator: class or method-level middleware
|
|
117
|
+
Get, Post, Put, Patch, Delete, Options, // method decorators
|
|
118
|
+
} from '@rudderjs/router'
|
|
119
|
+
|
|
120
|
+
import type { RouteDefinition, RouteBuilder } from '@rudderjs/router'
|
|
121
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rudderjs/router",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"files": [
|
|
12
|
-
"dist"
|
|
12
|
+
"dist",
|
|
13
|
+
"boost"
|
|
13
14
|
],
|
|
14
15
|
"main": "./dist/index.js",
|
|
15
16
|
"types": "./dist/index.d.ts",
|