@fjell/express-router 4.4.12 → 4.4.14
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 +332 -0
- package/docs/docs.config.ts +75 -0
- package/docs/index.html +18 -0
- package/docs/package-lock.json +5129 -0
- package/docs/package.json +34 -0
- package/docs/public/README.md +332 -0
- package/docs/public/examples-README.md +339 -0
- package/docs/public/fjell-icon.svg +1 -0
- package/docs/public/pano.png +0 -0
- package/docs/src/index.css +21 -0
- package/docs/src/main.tsx +12 -0
- package/docs/src/test/setup.ts +1 -0
- package/docs/src/types.d.ts +4 -0
- package/docs/tsconfig.node.json +15 -0
- package/package.json +16 -10
package/README.md
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# Fjell Express Router
|
|
2
|
+
|
|
3
|
+
**Express Router for Fjell** - Automatic REST API generation with hierarchical data management for Express.js applications.
|
|
4
|
+
|
|
5
|
+
Fjell Express Router provides a powerful abstraction layer for creating Express.js REST APIs that automatically handle CRUD operations for complex, hierarchical data models. Built on the Fjell framework, it enables rapid development of enterprise-grade APIs with built-in support for nested resources, business logic integration, and type-safe operations.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Automatic CRUD Routes**: Generate complete REST endpoints with minimal configuration
|
|
10
|
+
- **Hierarchical Data Support**: Handle complex nested relationships with parent-child routing
|
|
11
|
+
- **Type-Safe Operations**: Full TypeScript support with generic type constraints
|
|
12
|
+
- **Flexible Business Logic**: Easy integration of custom business rules and validations
|
|
13
|
+
- **Express.js Integration**: Seamless mounting as Express middleware with full compatibility
|
|
14
|
+
- **Built-in Error Handling**: Comprehensive error responses with proper HTTP status codes
|
|
15
|
+
- **Extensible Architecture**: Support for custom actions, facets, and middleware
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @fjell/express-router
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or with pnpm:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add @fjell/express-router
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { PItemRouter, createRegistry } from '@fjell/express-router';
|
|
33
|
+
import { Item } from '@fjell/core';
|
|
34
|
+
import express from 'express';
|
|
35
|
+
|
|
36
|
+
// Define your data model
|
|
37
|
+
interface User extends Item<'user'> {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
email: string;
|
|
41
|
+
role: 'admin' | 'user' | 'guest';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Create Express app and registry
|
|
45
|
+
const app = express();
|
|
46
|
+
const registry = createRegistry();
|
|
47
|
+
|
|
48
|
+
// Create instance and router
|
|
49
|
+
const userInstance = registry.getInstance(
|
|
50
|
+
'user',
|
|
51
|
+
userOperations, // Your business logic implementation
|
|
52
|
+
userOptions // Configuration options
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const userRouter = new PItemRouter(userInstance, 'user');
|
|
56
|
+
|
|
57
|
+
// Mount router - automatically creates CRUD endpoints
|
|
58
|
+
app.use('/api/users', userRouter.getRouter());
|
|
59
|
+
|
|
60
|
+
// Start server
|
|
61
|
+
app.listen(3000, () => {
|
|
62
|
+
console.log('Server running on http://localhost:3000');
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This automatically creates the following endpoints:
|
|
67
|
+
|
|
68
|
+
- `GET /api/users` - List all users
|
|
69
|
+
- `GET /api/users/:userPk` - Get specific user
|
|
70
|
+
- `POST /api/users` - Create new user
|
|
71
|
+
- `PUT /api/users/:userPk` - Update user
|
|
72
|
+
- `DELETE /api/users/:userPk` - Delete user
|
|
73
|
+
|
|
74
|
+
## Core Concepts
|
|
75
|
+
|
|
76
|
+
### Router Types
|
|
77
|
+
|
|
78
|
+
**PItemRouter** - For primary entities that exist independently:
|
|
79
|
+
```typescript
|
|
80
|
+
const userRouter = new PItemRouter(userInstance, 'user');
|
|
81
|
+
const productRouter = new PItemRouter(productInstance, 'product');
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**CItemRouter** - For child entities that belong to parent entities:
|
|
85
|
+
```typescript
|
|
86
|
+
const orderRouter = new PItemRouter(orderInstance, 'order');
|
|
87
|
+
const orderItemRouter = new CItemRouter(orderItemInstance, 'orderItem', orderRouter);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Hierarchical Routing
|
|
91
|
+
|
|
92
|
+
Create nested routes for complex relationships:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Organization -> Department -> Employee hierarchy
|
|
96
|
+
const orgRouter = new PItemRouter(orgInstance, 'organization');
|
|
97
|
+
const deptRouter = new CItemRouter(deptInstance, 'department', orgRouter);
|
|
98
|
+
const empRouter = new CItemRouter(empInstance, 'employee', deptRouter);
|
|
99
|
+
|
|
100
|
+
// Mount hierarchical routes
|
|
101
|
+
app.use('/api/organizations', orgRouter.getRouter());
|
|
102
|
+
app.use('/api/organizations/:organizationPk/departments', deptRouter.getRouter());
|
|
103
|
+
app.use('/api/organizations/:organizationPk/departments/:departmentPk/employees', empRouter.getRouter());
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This creates endpoints like:
|
|
107
|
+
- `GET /api/organizations/org-1/departments/dept-1/employees`
|
|
108
|
+
- `POST /api/organizations/org-1/departments/dept-1/employees`
|
|
109
|
+
- `GET /api/organizations/org-1/departments/dept-1/employees/emp-1`
|
|
110
|
+
|
|
111
|
+
## Advanced Usage
|
|
112
|
+
|
|
113
|
+
### Custom Business Logic
|
|
114
|
+
|
|
115
|
+
Add custom routes alongside automatic CRUD operations:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const router = userRouter.getRouter();
|
|
119
|
+
|
|
120
|
+
// Add custom business logic routes
|
|
121
|
+
router.get('/analytics', async (req, res) => {
|
|
122
|
+
const analytics = await userInstance.operations.getAnalytics();
|
|
123
|
+
res.json(analytics);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
router.post('/:userPk/activate', async (req, res) => {
|
|
127
|
+
const userPk = req.params.userPk;
|
|
128
|
+
const user = await userInstance.operations.activate(userPk);
|
|
129
|
+
res.json(user);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
app.use('/api/users', router);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Middleware Integration
|
|
136
|
+
|
|
137
|
+
Add Express middleware for authentication, validation, and more:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { authenticate, authorize, validateRequest } from './middleware';
|
|
141
|
+
|
|
142
|
+
// Global middleware
|
|
143
|
+
app.use(express.json());
|
|
144
|
+
app.use(authenticate);
|
|
145
|
+
|
|
146
|
+
// Router-specific middleware
|
|
147
|
+
const protectedRouter = userRouter.getRouter();
|
|
148
|
+
protectedRouter.use(authorize(['admin', 'user']));
|
|
149
|
+
protectedRouter.use('/sensitive-endpoint', validateRequest);
|
|
150
|
+
|
|
151
|
+
app.use('/api/users', protectedRouter);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Error Handling
|
|
155
|
+
|
|
156
|
+
Built-in error handling with proper HTTP status codes:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Automatic error responses for common scenarios:
|
|
160
|
+
// 404 - Entity not found
|
|
161
|
+
// 400 - Invalid request data
|
|
162
|
+
// 500 - Internal server errors
|
|
163
|
+
|
|
164
|
+
// Custom error handling
|
|
165
|
+
app.use((err, req, res, next) => {
|
|
166
|
+
console.error('API Error:', err);
|
|
167
|
+
res.status(err.status || 500).json({
|
|
168
|
+
error: err.message || 'Internal Server Error',
|
|
169
|
+
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Data Model Requirements
|
|
175
|
+
|
|
176
|
+
Your data models must extend the Fjell `Item` interface:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { Item, UUID } from '@fjell/core';
|
|
180
|
+
|
|
181
|
+
interface User extends Item<'user'> {
|
|
182
|
+
id: string;
|
|
183
|
+
name: string;
|
|
184
|
+
email: string;
|
|
185
|
+
// ... other properties
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
interface Order extends Item<'order'> {
|
|
189
|
+
id: string;
|
|
190
|
+
customerId: string;
|
|
191
|
+
total: number;
|
|
192
|
+
// ... other properties
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface OrderItem extends Item<'orderItem', 'order'> {
|
|
196
|
+
id: string;
|
|
197
|
+
productId: string;
|
|
198
|
+
quantity: number;
|
|
199
|
+
price: number;
|
|
200
|
+
// ... other properties
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Configuration
|
|
205
|
+
|
|
206
|
+
Configure your instances with business operations and options:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const userInstance = registry.getInstance(
|
|
210
|
+
'user',
|
|
211
|
+
{
|
|
212
|
+
// Business operations implementation
|
|
213
|
+
create: async (item) => { /* create logic */ },
|
|
214
|
+
get: async (pk) => { /* get logic */ },
|
|
215
|
+
update: async (pk, updates) => { /* update logic */ },
|
|
216
|
+
delete: async (pk) => { /* delete logic */ },
|
|
217
|
+
list: async (query) => { /* list logic */ },
|
|
218
|
+
// ... other operations
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
// Configuration options
|
|
222
|
+
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
223
|
+
validation: { /* validation rules */ },
|
|
224
|
+
facets: { /* custom facets */ },
|
|
225
|
+
actions: { /* custom actions */ },
|
|
226
|
+
// ... other options
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Examples
|
|
232
|
+
|
|
233
|
+
This package includes comprehensive examples in the `examples/` directory:
|
|
234
|
+
|
|
235
|
+
- **`basic-router-example.ts`** - Start here for fundamental usage patterns
|
|
236
|
+
- **`nested-router-example.ts`** - Hierarchical data management with organizations/departments/employees
|
|
237
|
+
- **`full-application-example.ts`** - Production-ready e-commerce application
|
|
238
|
+
|
|
239
|
+
Run examples:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Basic example
|
|
243
|
+
npx tsx examples/basic-router-example.ts
|
|
244
|
+
|
|
245
|
+
# Nested routing example
|
|
246
|
+
npx tsx examples/nested-router-example.ts
|
|
247
|
+
|
|
248
|
+
# Full application example
|
|
249
|
+
npx tsx examples/full-application-example.ts
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## API Reference
|
|
253
|
+
|
|
254
|
+
### PItemRouter<T, S>
|
|
255
|
+
|
|
256
|
+
Primary item router for top-level entities.
|
|
257
|
+
|
|
258
|
+
**Constructor**
|
|
259
|
+
```typescript
|
|
260
|
+
new PItemRouter<T, S>(instance: Instance<T, S>, keyType: S, options?: ItemRouterOptions)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Methods**
|
|
264
|
+
- `getRouter(): Router` - Get Express router instance
|
|
265
|
+
- `getPkType(): S` - Get primary key type
|
|
266
|
+
- `createItem(req, res)` - Handle POST requests
|
|
267
|
+
- `getItem(req, res)` - Handle GET requests for single items
|
|
268
|
+
- `updateItem(req, res)` - Handle PUT requests
|
|
269
|
+
- `deleteItem(req, res)` - Handle DELETE requests
|
|
270
|
+
|
|
271
|
+
### CItemRouter<T, S, L1, ...>
|
|
272
|
+
|
|
273
|
+
Child item router for nested entities.
|
|
274
|
+
|
|
275
|
+
**Constructor**
|
|
276
|
+
```typescript
|
|
277
|
+
new CItemRouter<T, S, L1>(
|
|
278
|
+
instance: Instance<T, S, L1>,
|
|
279
|
+
keyType: S,
|
|
280
|
+
parentRouter: ItemRouter<L1>,
|
|
281
|
+
options?: ItemRouterOptions
|
|
282
|
+
)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Inherits all methods from `ItemRouter` with additional parent-child relationship handling.
|
|
286
|
+
|
|
287
|
+
### createRegistry()
|
|
288
|
+
|
|
289
|
+
Factory function to create a new registry instance for managing multiple routers.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
const registry = createRegistry();
|
|
293
|
+
const instance = registry.getInstance(keyType, operations, options);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Requirements
|
|
297
|
+
|
|
298
|
+
- Node.js >= 21
|
|
299
|
+
- TypeScript >= 5.0
|
|
300
|
+
- Express.js >= 5.0
|
|
301
|
+
|
|
302
|
+
## Dependencies
|
|
303
|
+
|
|
304
|
+
- `@fjell/core` - Core Fjell framework types and utilities
|
|
305
|
+
- `@fjell/lib` - Fjell library components
|
|
306
|
+
- `@fjell/logging` - Structured logging for Fjell applications
|
|
307
|
+
- `@fjell/registry` - Registry management for Fjell instances
|
|
308
|
+
- `express` - Express.js web framework
|
|
309
|
+
- `deepmerge` - Deep object merging utility
|
|
310
|
+
|
|
311
|
+
## Contributing
|
|
312
|
+
|
|
313
|
+
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
|
|
314
|
+
|
|
315
|
+
1. Fork the repository
|
|
316
|
+
2. Create a feature branch
|
|
317
|
+
3. Make your changes with tests
|
|
318
|
+
4. Ensure all tests pass
|
|
319
|
+
5. Submit a pull request
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
Licensed under the Apache License 2.0. See the LICENSE file for details.
|
|
324
|
+
|
|
325
|
+
## Support
|
|
326
|
+
|
|
327
|
+
- **Documentation**: [Full documentation and guides](./docs/)
|
|
328
|
+
- **Examples**: [Comprehensive examples](./examples/)
|
|
329
|
+
- **Issues**: [GitHub Issues](https://github.com/getfjell/express-router/issues)
|
|
330
|
+
- **Discussions**: [GitHub Discussions](https://github.com/getfjell/express-router/discussions)
|
|
331
|
+
|
|
332
|
+
Built with care by the Fjell team.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
interface DocsConfig {
|
|
2
|
+
projectName: string;
|
|
3
|
+
basePath: string;
|
|
4
|
+
port: number;
|
|
5
|
+
branding: {
|
|
6
|
+
theme: string;
|
|
7
|
+
tagline: string;
|
|
8
|
+
logo?: string;
|
|
9
|
+
backgroundImage?: string;
|
|
10
|
+
primaryColor?: string;
|
|
11
|
+
accentColor?: string;
|
|
12
|
+
github?: string;
|
|
13
|
+
npm?: string;
|
|
14
|
+
};
|
|
15
|
+
sections: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
subtitle: string;
|
|
19
|
+
file: string;
|
|
20
|
+
}>;
|
|
21
|
+
filesToCopy: Array<{
|
|
22
|
+
source: string;
|
|
23
|
+
destination: string;
|
|
24
|
+
}>;
|
|
25
|
+
plugins?: any[];
|
|
26
|
+
version: {
|
|
27
|
+
source: string;
|
|
28
|
+
};
|
|
29
|
+
customContent?: {
|
|
30
|
+
[key: string]: (content: string) => string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const config: DocsConfig = {
|
|
35
|
+
projectName: 'Fjell Express Router',
|
|
36
|
+
basePath: '/express-router/',
|
|
37
|
+
port: 3004,
|
|
38
|
+
branding: {
|
|
39
|
+
theme: 'express-router',
|
|
40
|
+
tagline: 'Express Router for Fjell',
|
|
41
|
+
backgroundImage: '/pano.png',
|
|
42
|
+
github: 'https://github.com/getfjell/express-router',
|
|
43
|
+
npm: 'https://www.npmjs.com/package/@fjell/express-router'
|
|
44
|
+
},
|
|
45
|
+
sections: [
|
|
46
|
+
{
|
|
47
|
+
id: 'overview',
|
|
48
|
+
title: 'Getting Started',
|
|
49
|
+
subtitle: 'Express Router for Fjell',
|
|
50
|
+
file: '/README.md'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'examples',
|
|
54
|
+
title: 'Examples',
|
|
55
|
+
subtitle: 'Code examples & usage patterns',
|
|
56
|
+
file: '/examples-README.md'
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
filesToCopy: [
|
|
60
|
+
{
|
|
61
|
+
source: '../README.md',
|
|
62
|
+
destination: 'public/README.md'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
source: '../examples/README.md',
|
|
66
|
+
destination: 'public/examples-README.md'
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
plugins: [],
|
|
70
|
+
version: {
|
|
71
|
+
source: 'package.json'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default config
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/fjell-icon.svg" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<title>Fjell Express Router - Express Router for Fjell</title>
|
|
9
|
+
<meta name="description"
|
|
10
|
+
content="Express Router for Fjell - A powerful Express.js router integration for the Fjell framework">
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
16
|
+
</body>
|
|
17
|
+
|
|
18
|
+
</html>
|