@avleon/core 0.0.20 → 0.0.24
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 +559 -2
- package/dist/application.d.ts +26 -0
- package/dist/application.js +50 -0
- package/dist/collection.js +3 -2
- package/dist/container.d.ts +1 -0
- package/dist/container.js +2 -1
- package/dist/environment-variables.js +1 -1
- package/dist/file-storage.js +0 -128
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +41 -4
- package/dist/icore.d.ts +68 -26
- package/dist/icore.js +235 -212
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- package/dist/middleware.js +0 -8
- package/dist/multipart.js +4 -1
- package/dist/openapi.d.ts +37 -37
- package/dist/params.js +2 -2
- package/dist/response.js +6 -2
- package/dist/route-methods.js +1 -1
- package/dist/swagger-schema.js +4 -1
- package/dist/testing.js +5 -2
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/optional-require.d.ts +8 -0
- package/dist/utils/optional-require.js +70 -0
- package/dist/validation.d.ts +4 -1
- package/dist/validation.js +10 -5
- package/package.json +19 -11
- package/src/application.ts +96 -0
- package/src/authentication.ts +16 -0
- package/src/collection.ts +254 -0
- package/src/config.ts +39 -0
- package/src/constants.ts +1 -0
- package/src/container.ts +54 -0
- package/src/controller.ts +128 -0
- package/src/decorators.ts +27 -0
- package/src/environment-variables.ts +46 -0
- package/src/exceptions/http-exceptions.ts +86 -0
- package/src/exceptions/index.ts +1 -0
- package/src/exceptions/system-exception.ts +34 -0
- package/src/file-storage.ts +206 -0
- package/src/helpers.ts +328 -0
- package/src/icore.ts +1064 -0
- package/src/index.ts +30 -0
- package/src/logger.ts +72 -0
- package/src/map-types.ts +159 -0
- package/src/middleware.ts +98 -0
- package/src/multipart.ts +116 -0
- package/src/openapi.ts +372 -0
- package/src/params.ts +111 -0
- package/src/queue.ts +126 -0
- package/src/response.ts +117 -0
- package/src/results.ts +30 -0
- package/src/route-methods.ts +186 -0
- package/src/swagger-schema.ts +213 -0
- package/src/testing.ts +220 -0
- package/src/types/app-builder.interface.ts +19 -0
- package/src/types/application.interface.ts +9 -0
- package/src/utils/hash.ts +5 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/optional-require.ts +50 -0
- package/src/validation.ts +156 -0
- package/src/validator-extend.ts +25 -0
- package/dist/classToOpenapi.d.ts +0 -0
- package/dist/classToOpenapi.js +0 -1
- package/dist/render.d.ts +0 -1
- package/dist/render.js +0 -8
- package/jest.config.ts +0 -9
- package/tsconfig.json +0 -25
- /package/dist/{security.d.ts → utils/hash.d.ts} +0 -0
- /package/dist/{security.js → utils/hash.js} +0 -0
package/README.md
CHANGED
|
@@ -1,4 +1,561 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Avleon Core Framework
|
|
2
2
|
|
|
3
|
+
## Overview
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
Avleon is a powerful, TypeScript-based web framework built on top of Fastify, designed to simplify API development with a focus on decorators, dependency injection, and OpenAPI documentation. It provides a robust set of tools for building scalable, maintainable web applications with minimal boilerplate code.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
12
|
+
- [Core Concepts](#core-concepts)
|
|
13
|
+
- [Application Creation](#application-creation)
|
|
14
|
+
- [Controllers](#controllers)
|
|
15
|
+
- [Route Methods](#route-methods)
|
|
16
|
+
- [Parameter Decorators](#parameter-decorators)
|
|
17
|
+
- [Response Handling](#response-handling)
|
|
18
|
+
- [Middleware](#middleware)
|
|
19
|
+
- [Authentication & Authorization](#authentication--authorization)
|
|
20
|
+
- [Validation](#validation)
|
|
21
|
+
- [OpenAPI Documentation](#openapi-documentation)
|
|
22
|
+
- [Advanced Features](#advanced-features)
|
|
23
|
+
- [Database Integration](#database-integration)
|
|
24
|
+
- [File Uploads](#file-uploads)
|
|
25
|
+
- [Static Files](#static-files)
|
|
26
|
+
- [Testing](#testing)
|
|
27
|
+
- [Configuration](#configuration)
|
|
28
|
+
- [Route Mapping](#route-mapping)
|
|
29
|
+
- [mapGet](#mapget)
|
|
30
|
+
- [mapPost](#mappost)
|
|
31
|
+
- [mapPut](#mapput)
|
|
32
|
+
- [mapDelete](#mapdelete)
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Decorator-based API Development**: Define controllers, routes, and middleware using TypeScript decorators
|
|
37
|
+
- **Dependency Injection**: Built-in DI system using TypeDI for service management
|
|
38
|
+
- **OpenAPI/Swagger Integration**: Automatic API documentation generation with support for both Swagger UI and Scalar
|
|
39
|
+
- **Validation**: Request validation with support for class-validator and custom validation rules
|
|
40
|
+
- **Middleware System**: Flexible middleware architecture for request processing
|
|
41
|
+
- **Response Handling**: Standardized response formats with HTTP status codes
|
|
42
|
+
- **File Upload**: Built-in support for multipart file uploads with file validation
|
|
43
|
+
- **Authentication & Authorization**: Middleware for securing your API endpoints
|
|
44
|
+
- **Database Integration**: Support for TypeORM for database operations
|
|
45
|
+
- **Queue System**: Background job processing capabilities
|
|
46
|
+
- **Environment Configuration**: Environment variable management
|
|
47
|
+
- **Logging**: Integrated logging with Pino
|
|
48
|
+
- **Testing**: Built-in testing utilities for API endpoints
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install @avleon/core
|
|
54
|
+
# or
|
|
55
|
+
yarn add @avleon/core
|
|
56
|
+
# or
|
|
57
|
+
pnpm add @avleon/core
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { Avleon, ApiController, Get, Results } from '@avleon/core';
|
|
64
|
+
|
|
65
|
+
// Define a controller
|
|
66
|
+
@ApiController('/hello')
|
|
67
|
+
class HelloController {
|
|
68
|
+
@Get('/')
|
|
69
|
+
async sayHello() {
|
|
70
|
+
return Results.Ok({ message: 'Hello, Avleon!' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Create and start the application
|
|
75
|
+
const app = new Avleon({
|
|
76
|
+
controllers: [HelloController],
|
|
77
|
+
openapi: {
|
|
78
|
+
info: {
|
|
79
|
+
title: 'My Avleon API',
|
|
80
|
+
version: '1.0.0',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
app.start();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Core Concepts
|
|
89
|
+
|
|
90
|
+
### Application Creation
|
|
91
|
+
|
|
92
|
+
Avleon provides a builder pattern for creating applications:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { Builder } from '@avleon/core';
|
|
96
|
+
|
|
97
|
+
// Create an application using the builder
|
|
98
|
+
const builder = Builder.createAppBuilder();
|
|
99
|
+
const app = builder.build();
|
|
100
|
+
|
|
101
|
+
// Configure and start the application
|
|
102
|
+
app.useCors();
|
|
103
|
+
app.mapControllers([UserController]);
|
|
104
|
+
app.start(3000);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Controllers
|
|
108
|
+
|
|
109
|
+
Controllers are the entry points for your API requests. They are defined using the `@ApiController` decorator:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
@ApiController('/users')
|
|
113
|
+
class UserController {
|
|
114
|
+
// Route handlers go here
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
You can also specify controller options:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
@ApiController({
|
|
122
|
+
path: '/users',
|
|
123
|
+
name: 'User Management',
|
|
124
|
+
version: '1.0.0',
|
|
125
|
+
since: '2024-01-01'
|
|
126
|
+
})
|
|
127
|
+
class UserController {
|
|
128
|
+
// Route handlers go here
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Route Methods
|
|
133
|
+
|
|
134
|
+
Define HTTP methods using decorators:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
@Get('/')
|
|
138
|
+
async getUsers() {
|
|
139
|
+
// Handle GET request
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@Post('/')
|
|
143
|
+
async createUser(@Body() user: UserDto) {
|
|
144
|
+
// Handle POST request
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@Put('/:id')
|
|
148
|
+
async updateUser(@Param('id') id: string, @Body() user: UserDto) {
|
|
149
|
+
// Handle PUT request
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@Delete('/:id')
|
|
153
|
+
async deleteUser(@Param('id') id: string) {
|
|
154
|
+
// Handle DELETE request
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Parameter Decorators
|
|
159
|
+
|
|
160
|
+
Extract data from requests using parameter decorators:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
@Get('/:id')
|
|
164
|
+
async getUser(
|
|
165
|
+
@Param('id') id: string,
|
|
166
|
+
@Query('include') include: string,
|
|
167
|
+
@Header('authorization') token: string,
|
|
168
|
+
@Body() data: UserDto
|
|
169
|
+
) {
|
|
170
|
+
// Access route parameters, query strings, headers, and request body
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
You can also access the current user and files:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
@Post('/upload')
|
|
178
|
+
async uploadFile(
|
|
179
|
+
@User() currentUser: any,
|
|
180
|
+
@File() file: any
|
|
181
|
+
) {
|
|
182
|
+
// Access the current user and uploaded file
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@Post('/upload-multiple')
|
|
186
|
+
async uploadFiles(
|
|
187
|
+
@Files() files: any[]
|
|
188
|
+
) {
|
|
189
|
+
// Access multiple uploaded files
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Response Handling
|
|
194
|
+
|
|
195
|
+
Return standardized responses using the `Results` class:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
@Get('/:id')
|
|
199
|
+
async getUser(@Param('id') id: string) {
|
|
200
|
+
const user = await this.userService.findById(id);
|
|
201
|
+
|
|
202
|
+
if (!user) {
|
|
203
|
+
return Results.NotFound('User not found');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return Results.Ok(user);
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Middleware
|
|
211
|
+
|
|
212
|
+
Create and apply middleware for cross-cutting concerns:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
@Middleware
|
|
216
|
+
class LoggingMiddleware extends AppMiddleware {
|
|
217
|
+
async invoke(req: IRequest) {
|
|
218
|
+
console.log(`Request: ${req.method} ${req.url}`);
|
|
219
|
+
return req;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@UseMiddleware(LoggingMiddleware)
|
|
224
|
+
@ApiController('/users')
|
|
225
|
+
class UserController {
|
|
226
|
+
// Controller methods
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
You can also apply middleware to specific routes:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
@ApiController('/users')
|
|
234
|
+
class UserController {
|
|
235
|
+
@UseMiddleware(LoggingMiddleware)
|
|
236
|
+
@Get('/')
|
|
237
|
+
async getUsers() {
|
|
238
|
+
// Only this route will use the LoggingMiddleware
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Authentication & Authorization
|
|
244
|
+
|
|
245
|
+
Secure your API with authentication and authorization:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
@Authorize
|
|
249
|
+
class JwtAuthMiddleware extends AuthorizeMiddleware {
|
|
250
|
+
authorize(roles: string[]) {
|
|
251
|
+
return async (req: IRequest) => {
|
|
252
|
+
// Implement JWT authentication logic
|
|
253
|
+
return req;
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@Authorized()
|
|
259
|
+
@ApiController('/admin')
|
|
260
|
+
class AdminController {
|
|
261
|
+
// Protected controller methods
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Or protect specific routes with roles
|
|
265
|
+
@ApiController('/admin')
|
|
266
|
+
class AdminController {
|
|
267
|
+
@Authorized(['admin'])
|
|
268
|
+
@Get('/')
|
|
269
|
+
async adminDashboard() {
|
|
270
|
+
// Only users with 'admin' role can access this
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Validation
|
|
276
|
+
|
|
277
|
+
Validate request data using class-validator:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
class UserDto {
|
|
281
|
+
@IsString()
|
|
282
|
+
@IsNotEmpty()
|
|
283
|
+
name: string;
|
|
284
|
+
|
|
285
|
+
@IsEmail()
|
|
286
|
+
email: string;
|
|
287
|
+
|
|
288
|
+
@IsNumber()
|
|
289
|
+
@Min(0)
|
|
290
|
+
@Max(120)
|
|
291
|
+
age: number;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@Post('/')
|
|
295
|
+
async createUser(@Body() user: UserDto) {
|
|
296
|
+
// User data is automatically validated
|
|
297
|
+
return Results.Created(user);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
You can also use custom validation rules:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
class UserDto {
|
|
305
|
+
@Validate({
|
|
306
|
+
type: 'string',
|
|
307
|
+
required: true,
|
|
308
|
+
message: 'Name is required'
|
|
309
|
+
})
|
|
310
|
+
name: string;
|
|
311
|
+
|
|
312
|
+
@Validate({
|
|
313
|
+
type: 'number',
|
|
314
|
+
min: 0,
|
|
315
|
+
max: 120,
|
|
316
|
+
message: 'Age must be between 0 and 120'
|
|
317
|
+
})
|
|
318
|
+
age: number;
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### OpenAPI Documentation
|
|
323
|
+
|
|
324
|
+
Generate API documentation automatically:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const app = new Avleon({
|
|
328
|
+
controllers: [UserController],
|
|
329
|
+
openapi: {
|
|
330
|
+
info: {
|
|
331
|
+
title: 'User API',
|
|
332
|
+
version: '1.0.0',
|
|
333
|
+
description: 'API for managing users',
|
|
334
|
+
},
|
|
335
|
+
servers: [
|
|
336
|
+
{
|
|
337
|
+
url: 'http://localhost:3000',
|
|
338
|
+
description: 'Development server',
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
You can also customize the OpenAPI UI:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
app.useOpenApi(OpenApiConfig, (config) => {
|
|
349
|
+
// Modify the OpenAPI configuration
|
|
350
|
+
config.info.title = 'Custom API Title';
|
|
351
|
+
return config;
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// Or use Swagger UI with custom options
|
|
355
|
+
app.useSwagger({
|
|
356
|
+
routePrefix: '/api-docs',
|
|
357
|
+
ui: 'default', // or 'scalar' for Scalar UI
|
|
358
|
+
theme: {
|
|
359
|
+
// Custom theme options
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Advanced Features
|
|
365
|
+
|
|
366
|
+
### Database Integration
|
|
367
|
+
|
|
368
|
+
Connect to databases using TypeORM:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
const app = new Avleon({
|
|
372
|
+
controllers: [UserController],
|
|
373
|
+
database: {
|
|
374
|
+
type: 'postgres',
|
|
375
|
+
host: 'localhost',
|
|
376
|
+
port: 5432,
|
|
377
|
+
username: 'postgres',
|
|
378
|
+
password: 'password',
|
|
379
|
+
database: 'avleon',
|
|
380
|
+
entities: [User],
|
|
381
|
+
synchronize: true,
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Or use the builder pattern:
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
const builder = Builder.createAppBuilder();
|
|
390
|
+
builder.addDataSource(DatabaseConfig);
|
|
391
|
+
const app = builder.build();
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### File Uploads
|
|
395
|
+
|
|
396
|
+
Handle file uploads with multipart support:
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
// Configure multipart file uploads
|
|
400
|
+
app.useMultipart({
|
|
401
|
+
destination: path.join(process.cwd(), 'uploads'),
|
|
402
|
+
limits: {
|
|
403
|
+
fileSize: 5 * 1024 * 1024 // 5MB
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// In your controller
|
|
408
|
+
@Post('/upload')
|
|
409
|
+
async uploadFile(@File() file: any) {
|
|
410
|
+
// Process uploaded file
|
|
411
|
+
return Results.Ok({ filename: file.filename });
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Static Files
|
|
416
|
+
|
|
417
|
+
Serve static files:
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
app.useStaticFiles({
|
|
421
|
+
path: path.join(process.cwd(), 'public'),
|
|
422
|
+
prefix: '/static/'
|
|
423
|
+
});
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Testing
|
|
427
|
+
|
|
428
|
+
Test your API endpoints with the built-in testing utilities:
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { TestBuilder } from '@avleon/core';
|
|
432
|
+
|
|
433
|
+
const testBuilder = TestBuilder.createBuilder();
|
|
434
|
+
const app = testBuilder.getTestApplication({
|
|
435
|
+
controllers: [UserController]
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Test your API endpoints
|
|
439
|
+
const response = await app.get('/users');
|
|
440
|
+
expect(response.statusCode).toBe(200);
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Configuration
|
|
444
|
+
|
|
445
|
+
Configure your application with environment variables:
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
// .env
|
|
449
|
+
PORT=3000
|
|
450
|
+
DATABASE_URL=postgres://user:password@localhost:5432/db
|
|
451
|
+
|
|
452
|
+
// app.ts
|
|
453
|
+
import { Environment } from '@avleon/core';
|
|
454
|
+
|
|
455
|
+
const env = new Environment();
|
|
456
|
+
env.load();
|
|
457
|
+
|
|
458
|
+
const app = new Avleon({
|
|
459
|
+
controllers: [UserController],
|
|
460
|
+
env: {
|
|
461
|
+
port: 'PORT',
|
|
462
|
+
databaseUrl: 'DATABASE_URL',
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Route Mapping
|
|
468
|
+
|
|
469
|
+
Avleon provides several methods for mapping routes in your application:
|
|
470
|
+
|
|
471
|
+
### mapGet
|
|
472
|
+
|
|
473
|
+
The `mapGet` method is used to define GET routes in your application. It takes a path string and a handler function as parameters.
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
app.mapGet("/users", async (req, res) => {
|
|
477
|
+
// Handle GET request to /users
|
|
478
|
+
return { users: [] };
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### mapPost
|
|
483
|
+
|
|
484
|
+
The `mapPost` method is used to define POST routes in your application. It takes a path string and a handler function as parameters.
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
app.mapPost("/users", async (req, res) => {
|
|
488
|
+
// Handle POST request to /users
|
|
489
|
+
const userData = req.body;
|
|
490
|
+
// Process user data
|
|
491
|
+
return { success: true };
|
|
492
|
+
});
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### mapPut
|
|
496
|
+
|
|
497
|
+
The `mapPut` method is used to define PUT routes in your application. It takes a path string and a handler function as parameters.
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
app.mapPut("/users/:id", async (req, res) => {
|
|
501
|
+
// Handle PUT request to /users/:id
|
|
502
|
+
const userId = req.params.id;
|
|
503
|
+
const userData = req.body;
|
|
504
|
+
// Update user data
|
|
505
|
+
return { success: true };
|
|
506
|
+
});
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### mapDelete
|
|
510
|
+
|
|
511
|
+
The `mapDelete` method is used to define DELETE routes in your application. It takes a path string and a handler function as parameters.
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
app.mapDelete("/users/:id", async (req, res) => {
|
|
515
|
+
// Handle DELETE request to /users/:id
|
|
516
|
+
const userId = req.params.id;
|
|
517
|
+
// Delete user
|
|
518
|
+
return { success: true };
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Each of these methods returns a route object that can be used to add middleware or Swagger documentation to the route.
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
app.mapGet("/users", async (req, res) => {
|
|
526
|
+
// Handler function
|
|
527
|
+
})
|
|
528
|
+
.useMiddleware([AuthMiddleware])
|
|
529
|
+
.useSwagger({
|
|
530
|
+
summary: "Get all users",
|
|
531
|
+
description: "Retrieves a list of all users",
|
|
532
|
+
tags: ["users"],
|
|
533
|
+
response: {
|
|
534
|
+
200: {
|
|
535
|
+
description: "Successful response",
|
|
536
|
+
content: {
|
|
537
|
+
"application/json": {
|
|
538
|
+
schema: {
|
|
539
|
+
type: "array",
|
|
540
|
+
items: {
|
|
541
|
+
type: "object",
|
|
542
|
+
properties: {
|
|
543
|
+
id: { type: "string" },
|
|
544
|
+
name: { type: "string" }
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
## License
|
|
556
|
+
|
|
557
|
+
ISC
|
|
558
|
+
|
|
559
|
+
## Author
|
|
560
|
+
|
|
561
|
+
Tareq Hossain - [GitHub](https://github.com/xtareq)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Constructor } from "./helpers";
|
|
2
|
+
import { RouteShorthandMethod } from "fastify";
|
|
3
|
+
export interface InlineRoutes {
|
|
4
|
+
get: RouteShorthandMethod;
|
|
5
|
+
post: RouteShorthandMethod;
|
|
6
|
+
put: RouteShorthandMethod;
|
|
7
|
+
patch: RouteShorthandMethod;
|
|
8
|
+
delete: RouteShorthandMethod;
|
|
9
|
+
}
|
|
10
|
+
export interface Application {
|
|
11
|
+
inlineRoutes: () => InlineRoutes;
|
|
12
|
+
mapGroup: (path?: string | RegExp) => InlineRoutes;
|
|
13
|
+
/**
|
|
14
|
+
* Start the application
|
|
15
|
+
* @param port
|
|
16
|
+
* @returns void
|
|
17
|
+
*/
|
|
18
|
+
start: (port?: number) => void;
|
|
19
|
+
}
|
|
20
|
+
export interface TestApplication {
|
|
21
|
+
getController: <T>(controller: Constructor<T>) => T;
|
|
22
|
+
}
|
|
23
|
+
export declare class Builder {
|
|
24
|
+
static createApplication(): Application;
|
|
25
|
+
static createTestApplication(app?: Application): TestApplication;
|
|
26
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Builder = void 0;
|
|
7
|
+
const typedi_1 = __importDefault(require("typedi"));
|
|
8
|
+
const fastify_1 = __importDefault(require("fastify"));
|
|
9
|
+
class IqraTestApplication {
|
|
10
|
+
getController(controller) {
|
|
11
|
+
const con = typedi_1.default.get(controller);
|
|
12
|
+
return con;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class IqraApplication {
|
|
16
|
+
constructor() {
|
|
17
|
+
if (!this.app) {
|
|
18
|
+
this.app = fastify_1.default.prototype;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
inlineRoutes() {
|
|
22
|
+
return {
|
|
23
|
+
get: this.app.get,
|
|
24
|
+
post: this.app.post,
|
|
25
|
+
put: this.app.put,
|
|
26
|
+
patch: this.app.patch,
|
|
27
|
+
delete: this.app.delete
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
mapGroup(path) {
|
|
31
|
+
return this.inlineRoutes();
|
|
32
|
+
}
|
|
33
|
+
start(port) {
|
|
34
|
+
const p = port ? port : 4000;
|
|
35
|
+
this.app.listen({ port: p });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class Builder {
|
|
39
|
+
static createApplication() {
|
|
40
|
+
const app = new IqraApplication();
|
|
41
|
+
return app;
|
|
42
|
+
}
|
|
43
|
+
static createTestApplication(app) {
|
|
44
|
+
const testApp = new IqraTestApplication();
|
|
45
|
+
return testApp;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.Builder = Builder;
|
|
49
|
+
const app = Builder.createApplication();
|
|
50
|
+
const route = app.inlineRoutes();
|
package/dist/collection.js
CHANGED
|
@@ -45,7 +45,7 @@ class BasicCollection {
|
|
|
45
45
|
const item = this.items.find(predicate);
|
|
46
46
|
if (item) {
|
|
47
47
|
const index = this.items.indexOf(item);
|
|
48
|
-
this.items[index] =
|
|
48
|
+
this.items[index] = { ...item, ...updater };
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
51
|
throw new exceptions_1.NotFoundException("Item not found");
|
|
@@ -108,8 +108,9 @@ class AsynchronousCollection {
|
|
|
108
108
|
}
|
|
109
109
|
getRepository() {
|
|
110
110
|
if (!this.repo) {
|
|
111
|
-
const dataSourceKey =
|
|
111
|
+
const dataSourceKey = "idatasource";
|
|
112
112
|
const dataSource = typedi_1.default.get(dataSourceKey);
|
|
113
|
+
console.log('datasource', dataSource);
|
|
113
114
|
const repository = dataSource.getRepository(this.model);
|
|
114
115
|
this.repo = repository;
|
|
115
116
|
return repository;
|
package/dist/container.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @url https://github.com/xtareq
|
|
6
6
|
*/
|
|
7
7
|
import TypediContainer from "typedi";
|
|
8
|
+
export declare const FEATURE_KEY: unique symbol;
|
|
8
9
|
export declare const ROUTE_META_KEY: unique symbol;
|
|
9
10
|
export declare const CONTROLLER_META_KEY: unique symbol;
|
|
10
11
|
export declare const PARAM_META_KEY: unique symbol;
|
package/dist/container.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.API_CONTROLLER_METADATA_KEY = exports.AUTHORIZATION_META_KEY = exports.DATASOURCE_META_KEY = exports.REQUEST_HEADER_META_KEY = exports.REQUEST_USER_META_KEY = exports.REQUEST_BODY_FILES_KEY = exports.REQUEST_BODY_FILE_KEY = exports.REQUEST_BODY_META_KEY = exports.QUERY_META_KEY = exports.PARAM_META_KEY = exports.CONTROLLER_META_KEY = exports.ROUTE_META_KEY = void 0;
|
|
6
|
+
exports.API_CONTROLLER_METADATA_KEY = exports.AUTHORIZATION_META_KEY = exports.DATASOURCE_META_KEY = exports.REQUEST_HEADER_META_KEY = exports.REQUEST_USER_META_KEY = exports.REQUEST_BODY_FILES_KEY = exports.REQUEST_BODY_FILE_KEY = exports.REQUEST_BODY_META_KEY = exports.QUERY_META_KEY = exports.PARAM_META_KEY = exports.CONTROLLER_META_KEY = exports.ROUTE_META_KEY = exports.FEATURE_KEY = void 0;
|
|
7
7
|
exports.registerController = registerController;
|
|
8
8
|
exports.registerService = registerService;
|
|
9
9
|
exports.getRegisteredServices = getRegisteredServices;
|
|
@@ -17,6 +17,7 @@ exports.registerDataSource = registerDataSource;
|
|
|
17
17
|
* @url https://github.com/xtareq
|
|
18
18
|
*/
|
|
19
19
|
const typedi_1 = __importDefault(require("typedi"));
|
|
20
|
+
exports.FEATURE_KEY = Symbol.for("features");
|
|
20
21
|
exports.ROUTE_META_KEY = Symbol("iroute:options");
|
|
21
22
|
exports.CONTROLLER_META_KEY = Symbol("icontroller:options");
|
|
22
23
|
exports.PARAM_META_KEY = Symbol("iparam:options");
|
|
@@ -27,7 +27,7 @@ let Environment = class Environment {
|
|
|
27
27
|
try {
|
|
28
28
|
const fileContent = fs_1.default.readFileSync(filePath, 'utf8');
|
|
29
29
|
const parsedEnv = dotenv_1.default.parse(fileContent);
|
|
30
|
-
return
|
|
30
|
+
return { ...parsedEnv, ...process.env };
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
33
|
console.error(`Error parsing .env file: ${error}`);
|