fragment-ts 1.0.31 → 1.0.32
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/API.md +752 -0
- package/DOCS.md +555 -0
- package/README.md +76 -339
- package/USAGE.md +309 -1306
- package/dist/cli/commands/init.command.js +1 -1
- package/dist/core/decorators/exception-filter.decorator.d.ts +5 -0
- package/dist/core/decorators/exception-filter.decorator.d.ts.map +1 -0
- package/dist/core/decorators/exception-filter.decorator.js +23 -0
- package/dist/core/decorators/exception-filter.decorator.js.map +1 -0
- package/dist/core/decorators/guard.decorator.d.ts +5 -0
- package/dist/core/decorators/guard.decorator.d.ts.map +1 -0
- package/dist/core/decorators/guard.decorator.js +23 -0
- package/dist/core/decorators/guard.decorator.js.map +1 -0
- package/dist/core/decorators/interceptor.decorator.d.ts +5 -0
- package/dist/core/decorators/interceptor.decorator.d.ts.map +1 -0
- package/dist/core/decorators/interceptor.decorator.js +23 -0
- package/dist/core/decorators/interceptor.decorator.js.map +1 -0
- package/dist/core/decorators/middleware.decorator.d.ts +8 -0
- package/dist/core/decorators/middleware.decorator.d.ts.map +1 -0
- package/dist/core/decorators/middleware.decorator.js +28 -0
- package/dist/core/decorators/middleware.decorator.js.map +1 -0
- package/dist/core/metadata/metadata-keys.d.ts +1 -0
- package/dist/core/metadata/metadata-keys.d.ts.map +1 -1
- package/dist/core/metadata/metadata-keys.js +1 -0
- package/dist/core/metadata/metadata-keys.js.map +1 -1
- package/dist/core/metadata/metadata-storage.d.ts +18 -0
- package/dist/core/metadata/metadata-storage.d.ts.map +1 -1
- package/dist/core/metadata/metadata-storage.js +82 -0
- package/dist/core/metadata/metadata-storage.js.map +1 -1
- package/dist/web/application.d.ts.map +1 -1
- package/dist/web/application.js +74 -5
- package/dist/web/application.js.map +1 -1
- package/dist/web/interfaces.d.ts +5 -1
- package/dist/web/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/init.command.ts +1 -1
- package/src/core/decorators/exception-filter.decorator.ts +20 -0
- package/src/core/decorators/guard.decorator.ts +20 -0
- package/src/core/decorators/interceptor.decorator.ts +20 -0
- package/src/core/decorators/middleware.decorator.ts +25 -0
- package/src/core/metadata/metadata-keys.ts +1 -0
- package/src/core/metadata/metadata-storage.ts +114 -0
- package/src/web/application.ts +141 -6
- package/src/web/interfaces.ts +11 -2
package/DOCS.md
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
|
|
2
|
+
# In-Depth Documentation
|
|
3
|
+
|
|
4
|
+
## Architecture Overview
|
|
5
|
+
|
|
6
|
+
Fragment TS follows a component-based architecture with dependency injection at its core. The framework is designed around several key principles:
|
|
7
|
+
|
|
8
|
+
1. **Inversion of Control (IoC)**: Components declare their dependencies rather than creating them directly
|
|
9
|
+
2. **Separation of Concerns**: Clear separation between controllers, services, and repositories
|
|
10
|
+
3. **Convention over Configuration**: Automatic component scanning and registration
|
|
11
|
+
4. **Type Safety**: Leveraging TypeScript's type system for compile-time validation
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
### Core Components
|
|
16
|
+
|
|
17
|
+
1. **DI Container**: Manages the lifecycle and dependencies of all components
|
|
18
|
+
2. **Metadata Storage**: Stores decorator metadata for runtime processing
|
|
19
|
+
3. **Component Scanner**: Discovers and registers components automatically
|
|
20
|
+
4. **Web Application**: Configures and starts the Express server
|
|
21
|
+
5. **TypeORM Module**: Integrates TypeORM for database operations
|
|
22
|
+
|
|
23
|
+
## Dependency Injection System
|
|
24
|
+
|
|
25
|
+
### How It Works
|
|
26
|
+
|
|
27
|
+
The dependency injection system in Fragment TS works through a combination of decorators, TypeScript metadata, and reflection:
|
|
28
|
+
|
|
29
|
+
1. **Decorator Metadata Collection**:
|
|
30
|
+
- Class decorators (`@Service()`, `@Controller()`, etc.) register components with the metadata storage
|
|
31
|
+
- Property decorators (`@Autowired()`, `@InjectRepository()`, etc.) store metadata about dependencies
|
|
32
|
+
- Method and parameter decorators store route and handler information
|
|
33
|
+
|
|
34
|
+
2. **Component Registration**:
|
|
35
|
+
- During application bootstrap, the component scanner loads all relevant files
|
|
36
|
+
- The metadata storage is populated with component definitions
|
|
37
|
+
- Components are registered with the DI container
|
|
38
|
+
|
|
39
|
+
3. **Dependency Resolution**:
|
|
40
|
+
- When a component is requested, the container creates an instance
|
|
41
|
+
- Constructor parameters are resolved recursively
|
|
42
|
+
- Property dependencies are injected based on metadata
|
|
43
|
+
- Post-construction hooks are called
|
|
44
|
+
|
|
45
|
+
### Scopes
|
|
46
|
+
|
|
47
|
+
Fragment TS supports three scopes for components:
|
|
48
|
+
|
|
49
|
+
1. **Singleton (default)**: One instance per application
|
|
50
|
+
2. **Request**: One instance per HTTP request
|
|
51
|
+
3. **Transient**: New instance every time it's requested
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
@Injectable('singleton')
|
|
55
|
+
class DatabaseConnection {}
|
|
56
|
+
|
|
57
|
+
@Injectable('request')
|
|
58
|
+
class RequestContext {}
|
|
59
|
+
|
|
60
|
+
@Injectable('transient')
|
|
61
|
+
class RandomGenerator {}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Circular Dependencies
|
|
65
|
+
|
|
66
|
+
The framework detects circular dependencies during component resolution and throws meaningful errors:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
@Service()
|
|
70
|
+
class ServiceA {
|
|
71
|
+
@Autowired()
|
|
72
|
+
private serviceB!: ServiceB;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Service()
|
|
76
|
+
class ServiceB {
|
|
77
|
+
@Autowired()
|
|
78
|
+
private serviceA!: ServiceA; // This will cause a circular dependency error
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Component Lifecycle
|
|
83
|
+
|
|
84
|
+
Fragment TS components follow a well-defined lifecycle:
|
|
85
|
+
|
|
86
|
+
1. **Registration**: Component is registered with the container
|
|
87
|
+
2. **Instantiation**: Container creates a new instance
|
|
88
|
+
3. **Dependency Injection**: Dependencies are injected via constructor and properties
|
|
89
|
+
4. **Post-Construction**: `@PostConstruct` methods are called
|
|
90
|
+
5. **Usage**: Component is ready for use
|
|
91
|
+
6. **Destruction**: `@PreDestroy` methods are called before garbage collection
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
@Service()
|
|
95
|
+
class LifecycleService {
|
|
96
|
+
constructor() {
|
|
97
|
+
console.log('Constructor called');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@PostConstruct()
|
|
101
|
+
init() {
|
|
102
|
+
console.log('Post-construct called - dependencies are available');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@PreDestroy()
|
|
106
|
+
cleanup() {
|
|
107
|
+
console.log('Pre-destroy called - cleanup resources');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Web Layer
|
|
113
|
+
|
|
114
|
+
### Request Processing Pipeline
|
|
115
|
+
|
|
116
|
+
1. **Route Registration**:
|
|
117
|
+
- Controllers and routes are registered during application bootstrap
|
|
118
|
+
- Route metadata is stored in the metadata storage
|
|
119
|
+
|
|
120
|
+
2. **Request Handling**:
|
|
121
|
+
- Express middleware processes the incoming request
|
|
122
|
+
- Route handler is matched based on path and HTTP method
|
|
123
|
+
- Controller instance is retrieved from the container
|
|
124
|
+
- Route parameters are resolved and injected
|
|
125
|
+
- Handler method is invoked
|
|
126
|
+
|
|
127
|
+
3. **Response Processing**:
|
|
128
|
+
- Return value is automatically converted to JSON
|
|
129
|
+
- Error handling middleware processes any exceptions
|
|
130
|
+
|
|
131
|
+
### Middleware Integration
|
|
132
|
+
|
|
133
|
+
Fragment TS integrates with Express middleware through the underlying Express application:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const app = new FragmentWebApplication();
|
|
137
|
+
const expressApp = app.getExpressApp();
|
|
138
|
+
|
|
139
|
+
// Add custom middleware
|
|
140
|
+
expressApp.use('/api', apiMiddleware);
|
|
141
|
+
expressApp.use(errorHandler);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Database Integration
|
|
145
|
+
|
|
146
|
+
### TypeORM Configuration
|
|
147
|
+
|
|
148
|
+
TypeORM is configured via a JSON file (default: `fragment.json`):
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"type": "mysql",
|
|
153
|
+
"host": "localhost",
|
|
154
|
+
"port": 3306,
|
|
155
|
+
"username": "root",
|
|
156
|
+
"password": "password",
|
|
157
|
+
"database": "my_db",
|
|
158
|
+
"entities": ["dist/entities/**/*.js"],
|
|
159
|
+
"synchronize": true,
|
|
160
|
+
"logging": false
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Repository Pattern
|
|
165
|
+
|
|
166
|
+
Fragment TS encourages the repository pattern for data access:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// Entity
|
|
170
|
+
@Entity()
|
|
171
|
+
export class User {
|
|
172
|
+
@PrimaryGeneratedColumn()
|
|
173
|
+
id: number;
|
|
174
|
+
|
|
175
|
+
@Column()
|
|
176
|
+
name: string;
|
|
177
|
+
|
|
178
|
+
@Column()
|
|
179
|
+
email: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Repository interface
|
|
183
|
+
export interface UserRepository {
|
|
184
|
+
findAll(): Promise<User[]>;
|
|
185
|
+
findById(id: number): Promise<User | null>;
|
|
186
|
+
save(user: User): Promise<User>;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Fragment repository implementation
|
|
190
|
+
@Repository()
|
|
191
|
+
export class TypeOrmUserRepository implements UserRepository {
|
|
192
|
+
@InjectRepository(User)
|
|
193
|
+
private repo!: Repository<User>;
|
|
194
|
+
|
|
195
|
+
async findAll(): Promise<User[]> {
|
|
196
|
+
return this.repo.find();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async findById(id: number): Promise<User | null> {
|
|
200
|
+
return this.repo.findOneBy({ id });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async save(user: User): Promise<User> {
|
|
204
|
+
return this.repo.save(user);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Advanced Features
|
|
210
|
+
|
|
211
|
+
### Conditional Components
|
|
212
|
+
|
|
213
|
+
Components can be conditionally registered based on environment, class availability, or existing beans:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// Only register if Redis class is available
|
|
217
|
+
@AutoConfiguration()
|
|
218
|
+
@ConditionalOnClass(Redis)
|
|
219
|
+
class RedisConfiguration {}
|
|
220
|
+
|
|
221
|
+
// Only register if no other logger is available
|
|
222
|
+
@Service()
|
|
223
|
+
@ConditionalOnMissingBean(LoggerService)
|
|
224
|
+
class DefaultLoggerService implements LoggerService {}
|
|
225
|
+
|
|
226
|
+
// Only register if environment variable is set
|
|
227
|
+
@Service()
|
|
228
|
+
@ConditionalOnProperty('ENABLE_CACHE', 'true')
|
|
229
|
+
class CacheService {}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Configuration Properties
|
|
233
|
+
|
|
234
|
+
Application configuration can be injected from environment variables or config files:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
@Service()
|
|
238
|
+
class AppConfig {
|
|
239
|
+
@Value('${PORT:3000}')
|
|
240
|
+
port!: number;
|
|
241
|
+
|
|
242
|
+
@Value('${DATABASE_URL}')
|
|
243
|
+
databaseUrl!: string;
|
|
244
|
+
|
|
245
|
+
@Value('${FEATURE_FLAG_NEW_UI:false}')
|
|
246
|
+
featureFlagNewUi!: boolean;
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Testing Support
|
|
251
|
+
|
|
252
|
+
Fragment TS is designed for testability with minimal dependencies on framework internals:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// Unit test example
|
|
256
|
+
describe('UserService', () => {
|
|
257
|
+
let userService: UserService;
|
|
258
|
+
let mockUserRepository: jest.Mocked<UserRepository>;
|
|
259
|
+
|
|
260
|
+
beforeEach(() => {
|
|
261
|
+
mockUserRepository = {
|
|
262
|
+
findAll: jest.fn(),
|
|
263
|
+
findById: jest.fn()
|
|
264
|
+
} as any;
|
|
265
|
+
|
|
266
|
+
userService = new UserService();
|
|
267
|
+
Object.defineProperty(userService, 'userRepository', {
|
|
268
|
+
value: mockUserRepository
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should return all users', async () => {
|
|
273
|
+
const mockUsers = [{ id: 1, name: 'John' }];
|
|
274
|
+
mockUserRepository.findAll.mockResolvedValue(mockUsers);
|
|
275
|
+
|
|
276
|
+
const result = await userService.findAll();
|
|
277
|
+
|
|
278
|
+
expect(result).toEqual(mockUsers);
|
|
279
|
+
expect(mockUserRepository.findAll).toHaveBeenCalled();
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Performance Considerations
|
|
285
|
+
|
|
286
|
+
### Startup Time
|
|
287
|
+
|
|
288
|
+
Component scanning and dependency resolution happen during application startup. For large applications:
|
|
289
|
+
|
|
290
|
+
- Use conditional components to limit unnecessary registrations
|
|
291
|
+
- Consider lazy loading for heavy dependencies
|
|
292
|
+
- Split application into modules if necessary
|
|
293
|
+
|
|
294
|
+
### Memory Usage
|
|
295
|
+
|
|
296
|
+
- Singleton-scoped components are held in memory for the application lifetime
|
|
297
|
+
- Request-scoped components are created per request and should be lightweight
|
|
298
|
+
- Transient components are created on-demand and not cached
|
|
299
|
+
|
|
300
|
+
### Optimization Techniques
|
|
301
|
+
|
|
302
|
+
1. **Lazy Loading**:
|
|
303
|
+
```typescript
|
|
304
|
+
@Service()
|
|
305
|
+
class HeavyService {
|
|
306
|
+
@Lazy()
|
|
307
|
+
@Autowired()
|
|
308
|
+
private resourceIntensiveService!: ResourceIntensiveService;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
2. **Selective Component Scanning**:
|
|
313
|
+
```typescript
|
|
314
|
+
@FragmentApplication({
|
|
315
|
+
autoScan: false // Disable automatic scanning
|
|
316
|
+
})
|
|
317
|
+
class Application {}
|
|
318
|
+
|
|
319
|
+
// Manually register components
|
|
320
|
+
const container = DIContainer.getInstance();
|
|
321
|
+
container.register(UserService);
|
|
322
|
+
container.register(UserController);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
3. **Production Build**:
|
|
326
|
+
- Always use compiled JavaScript in production
|
|
327
|
+
- Enable tree-shaking and minification
|
|
328
|
+
- Use environment variables for configuration instead of config files when possible
|
|
329
|
+
|
|
330
|
+
## Error Handling
|
|
331
|
+
|
|
332
|
+
### Global Error Handling
|
|
333
|
+
|
|
334
|
+
Fragment TS provides a global error handler that catches unhandled exceptions:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
const app = new FragmentWebApplication();
|
|
338
|
+
|
|
339
|
+
// Custom error handler
|
|
340
|
+
class CustomErrorHandler {
|
|
341
|
+
@PostConstruct()
|
|
342
|
+
register() {
|
|
343
|
+
const expressApp = app.getExpressApp();
|
|
344
|
+
expressApp.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
345
|
+
console.error('Global error:', err);
|
|
346
|
+
res.status(500).json({
|
|
347
|
+
error: 'Internal Server Error',
|
|
348
|
+
message: process.env.NODE_ENV === 'development' ? err.message : undefined
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Custom Error Types
|
|
356
|
+
|
|
357
|
+
Define custom error types for better error handling:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
export class NotFoundError extends Error {
|
|
361
|
+
constructor(message: string) {
|
|
362
|
+
super(message);
|
|
363
|
+
this.name = 'NotFoundError';
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export class ValidationError extends Error {
|
|
368
|
+
constructor(public errors: any[]) {
|
|
369
|
+
super('Validation failed');
|
|
370
|
+
this.name = 'ValidationError';
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Extensibility
|
|
376
|
+
|
|
377
|
+
### Custom Decorators
|
|
378
|
+
|
|
379
|
+
Create custom decorators by leveraging the metadata storage:
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
function CustomDecorator(metadata: any): MethodDecorator {
|
|
383
|
+
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
384
|
+
const storage = MetadataStorage.getInstance();
|
|
385
|
+
storage.addCustomMetadata(target.constructor, propertyKey, metadata);
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Usage
|
|
390
|
+
class MyController {
|
|
391
|
+
@CustomDecorator({ role: 'admin' })
|
|
392
|
+
adminMethod() {}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Custom Modules
|
|
397
|
+
|
|
398
|
+
Extend the framework with custom modules:
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
class CustomModule {
|
|
402
|
+
static async initialize() {
|
|
403
|
+
// Custom initialization logic
|
|
404
|
+
console.log('Custom module initialized');
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
static getDependency() {
|
|
408
|
+
// Return dependency for injection
|
|
409
|
+
return new CustomDependency();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Register with application
|
|
414
|
+
@FragmentApplication()
|
|
415
|
+
class Application {
|
|
416
|
+
constructor() {
|
|
417
|
+
CustomModule.initialize();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Best Practices
|
|
423
|
+
|
|
424
|
+
### Component Design
|
|
425
|
+
|
|
426
|
+
1. **Single Responsibility**: Each component should have one clear responsibility
|
|
427
|
+
2. **Loose Coupling**: Depend on abstractions (interfaces) rather than concrete implementations
|
|
428
|
+
3. **High Cohesion**: Related functionality should be grouped together
|
|
429
|
+
|
|
430
|
+
### Code Organization
|
|
431
|
+
|
|
432
|
+
1. **Feature-based Structure**:
|
|
433
|
+
```
|
|
434
|
+
src/
|
|
435
|
+
├── features/
|
|
436
|
+
│ ├── user/
|
|
437
|
+
│ │ ├── user.controller.ts
|
|
438
|
+
│ │ ├── user.service.ts
|
|
439
|
+
│ │ ├── user.repository.ts
|
|
440
|
+
│ │ ├── user.entity.ts
|
|
441
|
+
│ │ └── index.ts
|
|
442
|
+
│ └── product/
|
|
443
|
+
│ ├── product.controller.ts
|
|
444
|
+
│ └── ...
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
2. **Layer-based Structure**:
|
|
448
|
+
```
|
|
449
|
+
src/
|
|
450
|
+
├── controllers/
|
|
451
|
+
├── services/
|
|
452
|
+
├── repositories/
|
|
453
|
+
├── entities/
|
|
454
|
+
└── dtos/
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Testing Strategy
|
|
458
|
+
|
|
459
|
+
1. **Unit Tests**: Test individual components in isolation
|
|
460
|
+
2. **Integration Tests**: Test component interactions
|
|
461
|
+
3. **End-to-End Tests**: Test full request/response cycle
|
|
462
|
+
|
|
463
|
+
## Migration Guide
|
|
464
|
+
|
|
465
|
+
### From Express
|
|
466
|
+
|
|
467
|
+
1. Create a Fragment application class:
|
|
468
|
+
```typescript
|
|
469
|
+
@FragmentApplication()
|
|
470
|
+
class Application {}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
2. Convert Express routes to controllers:
|
|
474
|
+
```typescript
|
|
475
|
+
// Before (Express)
|
|
476
|
+
app.get('/users', (req, res) => {
|
|
477
|
+
// handler
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// After (Fragment)
|
|
481
|
+
@Controller('/users')
|
|
482
|
+
class UserController {
|
|
483
|
+
@Get()
|
|
484
|
+
findAll() {
|
|
485
|
+
// handler
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
3. Extract business logic to services:
|
|
491
|
+
```typescript
|
|
492
|
+
// Before
|
|
493
|
+
app.post('/users', async (req, res) => {
|
|
494
|
+
const user = await db.users.create(req.body);
|
|
495
|
+
res.json(user);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// After
|
|
499
|
+
@Service()
|
|
500
|
+
class UserService {
|
|
501
|
+
@Autowired()
|
|
502
|
+
private userRepository!: UserRepository;
|
|
503
|
+
|
|
504
|
+
async create(userData: any) {
|
|
505
|
+
return this.userRepository.save(userData);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
@Controller('/users')
|
|
510
|
+
class UserController {
|
|
511
|
+
@Autowired()
|
|
512
|
+
private userService!: UserService;
|
|
513
|
+
|
|
514
|
+
@Post()
|
|
515
|
+
async create(@Body() userData: any) {
|
|
516
|
+
return this.userService.create(userData);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### From NestJS
|
|
522
|
+
|
|
523
|
+
Fragment TS shares many concepts with NestJS:
|
|
524
|
+
|
|
525
|
+
1. **Dependency Injection**: Similar `@Injectable()`, `@Autowired()` patterns
|
|
526
|
+
2. **Controllers and Services**: Nearly identical structure
|
|
527
|
+
3. **TypeORM Integration**: Similar repository patterns
|
|
528
|
+
|
|
529
|
+
Key differences:
|
|
530
|
+
- Fragment TS uses property injection by default instead of constructor injection
|
|
531
|
+
- Simpler configuration with less boilerplate
|
|
532
|
+
- More lightweight with fewer dependencies
|
|
533
|
+
|
|
534
|
+
## Roadmap
|
|
535
|
+
|
|
536
|
+
### Planned Features
|
|
537
|
+
|
|
538
|
+
1. **Request-scoped Components**: Full support for request-scoped dependencies
|
|
539
|
+
2. **Validation Pipelines**: Built-in validation decorators
|
|
540
|
+
3. **Swagger Integration**: Automatic API documentation
|
|
541
|
+
4. **WebSockets Support**: Real-time communication capabilities
|
|
542
|
+
5. **CLI Tooling**: Project generation and management commands
|
|
543
|
+
|
|
544
|
+
### Community Contributions
|
|
545
|
+
|
|
546
|
+
Fragment TS welcomes community contributions:
|
|
547
|
+
|
|
548
|
+
1. **Bug Reports**: Report issues with reproduction steps
|
|
549
|
+
2. **Feature Requests**: Suggest new features and improvements
|
|
550
|
+
3. **Pull Requests**: Contribute code following the contribution guidelines
|
|
551
|
+
4. **Documentation**: Improve documentation and examples
|
|
552
|
+
|
|
553
|
+
## License
|
|
554
|
+
|
|
555
|
+
Fragment TS is released under the MIT License. See [LICENSE](LICENSE) for details.
|