@athenna/http 4.6.0 → 4.8.0
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 +22 -28
- package/src/annotations/Controller.js +8 -6
- package/src/annotations/Interceptor.js +15 -15
- package/src/annotations/Middleware.js +15 -15
- package/src/annotations/Terminator.js +15 -15
- package/src/exceptions/NotFoundControllerException.d.ts +12 -0
- package/src/exceptions/NotFoundControllerException.js +19 -0
- package/src/exceptions/NotFoundMiddlewareException.d.ts +12 -0
- package/src/exceptions/NotFoundMiddlewareException.js +19 -0
- package/src/kernels/HttpKernel.d.ts +9 -0
- package/src/kernels/HttpKernel.js +86 -32
- package/src/providers/HttpRouteProvider.js +1 -1
- package/src/providers/HttpServerProvider.js +1 -1
- package/src/router/Route.js +35 -10
- package/src/types/controllers/ControllerOptions.d.ts +13 -5
- package/src/types/middlewares/MiddlewareOptions.d.ts +14 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@athenna/http",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"description": "The Athenna Http server. Built on top of fastify.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "João Lenon <lenon@athenna.io>",
|
|
@@ -66,17 +66,14 @@
|
|
|
66
66
|
"#tests/*": "./tests/*.js",
|
|
67
67
|
"#tests": "./tests/index.js"
|
|
68
68
|
},
|
|
69
|
-
"dependencies": {
|
|
70
|
-
"fastify": "^4.21.0"
|
|
71
|
-
},
|
|
72
69
|
"devDependencies": {
|
|
73
|
-
"@athenna/artisan": "^4.
|
|
74
|
-
"@athenna/common": "^4.
|
|
70
|
+
"@athenna/artisan": "^4.10.0",
|
|
71
|
+
"@athenna/common": "^4.11.0",
|
|
75
72
|
"@athenna/config": "^4.4.0",
|
|
76
|
-
"@athenna/ioc": "^4.
|
|
77
|
-
"@athenna/logger": "^4.
|
|
78
|
-
"@athenna/test": "^4.
|
|
79
|
-
"@athenna/view": "^4.
|
|
73
|
+
"@athenna/ioc": "^4.4.0",
|
|
74
|
+
"@athenna/logger": "^4.4.0",
|
|
75
|
+
"@athenna/test": "^4.7.0",
|
|
76
|
+
"@athenna/view": "^4.3.0",
|
|
80
77
|
"@fastify/cors": "^8.1.1",
|
|
81
78
|
"@fastify/helmet": "^10.0.2",
|
|
82
79
|
"@fastify/rate-limit": "^7.5.0",
|
|
@@ -209,30 +206,27 @@
|
|
|
209
206
|
"providers": [],
|
|
210
207
|
"controllers": [
|
|
211
208
|
"#tests/fixtures/controllers/HelloController",
|
|
212
|
-
"#tests/fixtures/controllers/
|
|
209
|
+
"#tests/fixtures/controllers/AnnotatedController"
|
|
213
210
|
],
|
|
214
211
|
"middlewares": [
|
|
215
|
-
"#tests/fixtures/middlewares/
|
|
216
|
-
"#tests/fixtures/middlewares/ImportedMiddleware"
|
|
217
|
-
"#tests/fixtures/middlewares/DecoratedMiddleware",
|
|
218
|
-
"#tests/fixtures/middlewares/DecoratedInterceptor",
|
|
219
|
-
"#tests/fixtures/middlewares/DecoratedTerminator"
|
|
212
|
+
"#tests/fixtures/middlewares/MyMiddleware",
|
|
213
|
+
"#tests/fixtures/middlewares/ImportedMiddleware"
|
|
220
214
|
],
|
|
221
215
|
"namedMiddlewares": {
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"
|
|
225
|
-
"not-found-middleware": "#tests/fixtures/middlewares/
|
|
226
|
-
"not-found-interceptor": "#tests/fixtures/middlewares/
|
|
227
|
-
"not-found-terminator": "#tests/fixtures/middlewares/
|
|
216
|
+
"myMiddleware": "#tests/fixtures/middlewares/MyMiddleware",
|
|
217
|
+
"myInterceptor": "#tests/fixtures/middlewares/MyInterceptor",
|
|
218
|
+
"myTerminator": "#tests/fixtures/middlewares/MyTerminator",
|
|
219
|
+
"not-found-middleware": "#tests/fixtures/middlewares/AnnotatedMiddleware",
|
|
220
|
+
"not-found-interceptor": "#tests/fixtures/middlewares/AnnotatedInterceptor",
|
|
221
|
+
"not-found-terminator": "#tests/fixtures/middlewares/AnnotatedTerminator"
|
|
228
222
|
},
|
|
229
223
|
"globalMiddlewares": [
|
|
230
|
-
"#tests/fixtures/middlewares/
|
|
231
|
-
"#tests/fixtures/middlewares/
|
|
232
|
-
"#tests/fixtures/middlewares/
|
|
233
|
-
"#tests/fixtures/middlewares/
|
|
234
|
-
"#tests/fixtures/middlewares/
|
|
235
|
-
"#tests/fixtures/middlewares/
|
|
224
|
+
"#tests/fixtures/middlewares/MyMiddleware",
|
|
225
|
+
"#tests/fixtures/middlewares/MyInterceptor",
|
|
226
|
+
"#tests/fixtures/middlewares/MyTerminator",
|
|
227
|
+
"#tests/fixtures/middlewares/AnnotatedGlobalMiddleware",
|
|
228
|
+
"#tests/fixtures/middlewares/AnnotatedGlobalInterceptor",
|
|
229
|
+
"#tests/fixtures/middlewares/AnnotatedGlobalTerminator"
|
|
236
230
|
],
|
|
237
231
|
"commands": {
|
|
238
232
|
"route:list": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import 'reflect-metadata';
|
|
10
10
|
import { debug } from '#src/debug';
|
|
11
11
|
import { Options } from '@athenna/common';
|
|
12
|
+
import { Annotation } from '@athenna/ioc';
|
|
12
13
|
/**
|
|
13
14
|
* Create a controller inside the service provider.
|
|
14
15
|
*/
|
|
@@ -18,13 +19,14 @@ export function Controller(options) {
|
|
|
18
19
|
alias: `App/Http/Controllers/${target.name}`,
|
|
19
20
|
type: 'transient'
|
|
20
21
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
debug('Registering controller metadata for the service container %o', {
|
|
23
|
+
name: target.name,
|
|
24
|
+
...options
|
|
25
|
+
});
|
|
26
|
+
if (ioc.has(options.alias) || ioc.has(options.camelAlias)) {
|
|
27
|
+
debug('Skipping registration, controller is already registered.');
|
|
25
28
|
return;
|
|
26
29
|
}
|
|
27
|
-
|
|
28
|
-
Reflect.defineMetadata('ioc:registered', true, target);
|
|
30
|
+
Annotation.defineMeta(target, options);
|
|
29
31
|
};
|
|
30
32
|
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
9
|
import 'reflect-metadata';
|
|
10
|
-
import {
|
|
10
|
+
import { debug } from '#src/debug';
|
|
11
|
+
import { Annotation } from '@athenna/ioc';
|
|
11
12
|
import { Options, String } from '@athenna/common';
|
|
12
|
-
import { debug } from '#src/debug/index';
|
|
13
13
|
/**
|
|
14
14
|
* Create an interceptor inside the service provider.
|
|
15
15
|
*/
|
|
@@ -17,24 +17,24 @@ export function Interceptor(options) {
|
|
|
17
17
|
return (target) => {
|
|
18
18
|
options = Options.create(options, {
|
|
19
19
|
isGlobal: false,
|
|
20
|
-
|
|
20
|
+
type: 'transient',
|
|
21
21
|
alias: `App/Http/Interceptors/${target.name}`,
|
|
22
|
-
|
|
22
|
+
name: String.toCamelCase(target.name)
|
|
23
23
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
options.name = `App/Http/Interceptors/Names/${options.name}`;
|
|
25
|
+
debug('Registering interceptor metadata for the service container %o', {
|
|
26
|
+
...options,
|
|
27
|
+
name: target.name,
|
|
28
|
+
namedAlias: options.name
|
|
29
|
+
});
|
|
30
|
+
if (ioc.has(options.name)) {
|
|
31
|
+
debug('Skipping registration, named alias %s is already registered.', options.name);
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
30
|
-
ioc
|
|
31
|
-
|
|
32
|
-
if (!options.isGlobal) {
|
|
33
|
-
ioc.alias(`App/Http/Interceptors/Names/${options.name}`, alias);
|
|
34
|
+
if (ioc.has(options.alias)) {
|
|
35
|
+
debug('Skipping registration, alias %s is already registered.', options.alias);
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
debug('Registering %s as a global interceptor via Interceptor annotation.', Interceptor.constructor.name);
|
|
38
|
-
Server.intercept(Interceptor.intercept);
|
|
38
|
+
Annotation.defineMeta(target, options);
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
9
|
import 'reflect-metadata';
|
|
10
|
-
import {
|
|
10
|
+
import { debug } from '#src/debug';
|
|
11
|
+
import { Annotation } from '@athenna/ioc';
|
|
11
12
|
import { Options, String } from '@athenna/common';
|
|
12
|
-
import { debug } from '#src/debug/index';
|
|
13
13
|
/**
|
|
14
14
|
* Create a middleware inside the service provider.
|
|
15
15
|
*/
|
|
@@ -17,24 +17,24 @@ export function Middleware(options) {
|
|
|
17
17
|
return (target) => {
|
|
18
18
|
options = Options.create(options, {
|
|
19
19
|
isGlobal: false,
|
|
20
|
-
|
|
20
|
+
type: 'transient',
|
|
21
21
|
alias: `App/Http/Middlewares/${target.name}`,
|
|
22
|
-
|
|
22
|
+
name: String.toCamelCase(target.name)
|
|
23
23
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
options.name = `App/Http/Middlewares/Names/${options.name}`;
|
|
25
|
+
debug('Registering middleware metadata for the service container %o', {
|
|
26
|
+
...options,
|
|
27
|
+
name: target.name,
|
|
28
|
+
namedAlias: options.name
|
|
29
|
+
});
|
|
30
|
+
if (ioc.has(options.name)) {
|
|
31
|
+
debug('Skipping registration, named alias %s is already registered.', options.name);
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
30
|
-
ioc
|
|
31
|
-
|
|
32
|
-
if (!options.isGlobal) {
|
|
33
|
-
ioc.alias(`App/Http/Middlewares/Names/${options.name}`, alias);
|
|
34
|
+
if (ioc.has(options.alias)) {
|
|
35
|
+
debug('Skipping registration, alias %s is already registered.', options.alias);
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
debug('Registering %s as a global middleware via Middleware annotation.', Middleware.constructor.name);
|
|
38
|
-
Server.middleware(Middleware.handle);
|
|
38
|
+
Annotation.defineMeta(target, options);
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
9
|
import 'reflect-metadata';
|
|
10
|
-
import {
|
|
10
|
+
import { debug } from '#src/debug';
|
|
11
|
+
import { Annotation } from '@athenna/ioc';
|
|
11
12
|
import { Options, String } from '@athenna/common';
|
|
12
|
-
import { debug } from '#src/debug/index';
|
|
13
13
|
/**
|
|
14
14
|
* Create a terminator inside the service provider.
|
|
15
15
|
*/
|
|
@@ -17,24 +17,24 @@ export function Terminator(options) {
|
|
|
17
17
|
return (target) => {
|
|
18
18
|
options = Options.create(options, {
|
|
19
19
|
isGlobal: false,
|
|
20
|
-
|
|
20
|
+
type: 'transient',
|
|
21
21
|
alias: `App/Http/Terminators/${target.name}`,
|
|
22
|
-
|
|
22
|
+
name: String.toCamelCase(target.name)
|
|
23
23
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
options.name = `App/Http/Terminators/Names/${options.name}`;
|
|
25
|
+
debug('Registering terminator metadata for the service container %o', {
|
|
26
|
+
...options,
|
|
27
|
+
name: target.name,
|
|
28
|
+
namedAlias: options.name
|
|
29
|
+
});
|
|
30
|
+
if (ioc.has(options.name)) {
|
|
31
|
+
debug('Skipping registration, named alias %s is already registered.', options.name);
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
30
|
-
ioc
|
|
31
|
-
|
|
32
|
-
if (!options.isGlobal) {
|
|
33
|
-
ioc.alias(`App/Http/Terminators/Names/${options.name}`, alias);
|
|
34
|
+
if (ioc.has(options.alias)) {
|
|
35
|
+
debug('Skipping registration, alias %s is already registered.', options.alias);
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
debug('Registering %s as a global terminator via Terminator annotation.', Terminator.constructor.name);
|
|
38
|
-
Server.middleware(Terminator.terminate);
|
|
38
|
+
Annotation.defineMeta(target, options);
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @athenna/ioc
|
|
3
|
+
*
|
|
4
|
+
* (c) João Lenon <lenon@athenna.io>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { Exception } from '@athenna/common';
|
|
10
|
+
export declare class NotFoundControllerException extends Exception {
|
|
11
|
+
constructor(alias: string);
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @athenna/ioc
|
|
3
|
+
*
|
|
4
|
+
* (c) João Lenon <lenon@athenna.io>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { Exception } from '@athenna/common';
|
|
10
|
+
export class NotFoundControllerException extends Exception {
|
|
11
|
+
constructor(alias) {
|
|
12
|
+
super({
|
|
13
|
+
status: 500,
|
|
14
|
+
code: 'E_NOT_FOUND_CONTROLLER_ERROR',
|
|
15
|
+
message: `The controller with ${alias} alias has not been found inside the container.`,
|
|
16
|
+
help: `Remember to register the controller in your .athennarc.json file.`
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @athenna/ioc
|
|
3
|
+
*
|
|
4
|
+
* (c) João Lenon <lenon@athenna.io>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { Exception } from '@athenna/common';
|
|
10
|
+
export declare class NotFoundMiddlewareException extends Exception {
|
|
11
|
+
constructor(alias: string, namedAlias: string);
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @athenna/ioc
|
|
3
|
+
*
|
|
4
|
+
* (c) João Lenon <lenon@athenna.io>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { Exception } from '@athenna/common';
|
|
10
|
+
export class NotFoundMiddlewareException extends Exception {
|
|
11
|
+
constructor(alias, namedAlias) {
|
|
12
|
+
super({
|
|
13
|
+
status: 500,
|
|
14
|
+
code: 'E_NOT_FOUND_MIDDLEWARE_ERROR',
|
|
15
|
+
message: `The middleware with ${namedAlias} named alias and ${alias} alias has not been found inside the container.`,
|
|
16
|
+
help: `Remember to register the middleware in your .athennarc.json file.`
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -74,4 +74,13 @@ export declare class HttpKernel {
|
|
|
74
74
|
* Resolve the import path by meta URL and import it.
|
|
75
75
|
*/
|
|
76
76
|
private resolvePath;
|
|
77
|
+
/**
|
|
78
|
+
* Register the controllers using the meta information
|
|
79
|
+
* defined by annotations.
|
|
80
|
+
*/
|
|
81
|
+
private registerUsingMeta;
|
|
82
|
+
/**
|
|
83
|
+
* Get the configuration for the given key.
|
|
84
|
+
*/
|
|
85
|
+
private getConfig;
|
|
77
86
|
}
|
|
@@ -12,7 +12,8 @@ import { debug } from '#src/debug';
|
|
|
12
12
|
import { Log } from '@athenna/logger';
|
|
13
13
|
import { Config } from '@athenna/config';
|
|
14
14
|
import { isAbsolute, resolve } from 'node:path';
|
|
15
|
-
import {
|
|
15
|
+
import { Annotation } from '@athenna/ioc';
|
|
16
|
+
import { File, Exec, Module, String } from '@athenna/common';
|
|
16
17
|
import { HttpExceptionHandler } from '#src/handlers/HttpExceptionHandler';
|
|
17
18
|
const corsPlugin = await Module.safeImport('@fastify/cors');
|
|
18
19
|
const helmetPlugin = await Module.safeImport('@fastify/helmet');
|
|
@@ -25,26 +26,38 @@ export class HttpKernel {
|
|
|
25
26
|
* Register the @fastify/cors plugin in the Http server.
|
|
26
27
|
*/
|
|
27
28
|
async registerCors() {
|
|
29
|
+
if (Config.is('http.cors.enabled', false)) {
|
|
30
|
+
debug('Not able to register cors plugin. Set the http.cors.enabled configuration as true.');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
28
33
|
if (!corsPlugin) {
|
|
29
34
|
debug('Not able to register cors plugin. Install @fastify/cors package.');
|
|
30
35
|
return;
|
|
31
36
|
}
|
|
32
|
-
await Server.plugin(corsPlugin,
|
|
37
|
+
await Server.plugin(corsPlugin, this.getConfig('http.cors'));
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* Register the @fastify/helmet plugin in the Http server.
|
|
36
41
|
*/
|
|
37
42
|
async registerHelmet() {
|
|
43
|
+
if (Config.is('http.helmet.enabled', false)) {
|
|
44
|
+
debug('Not able to register helmet plugin. Set the http.helmet.enabled configuration as true.');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
38
47
|
if (!helmetPlugin) {
|
|
39
48
|
debug('Not able to register helmet plugin. Install @fastify/helmet package.');
|
|
40
49
|
return;
|
|
41
50
|
}
|
|
42
|
-
await Server.plugin(helmetPlugin,
|
|
51
|
+
await Server.plugin(helmetPlugin, this.getConfig('http.helmet'));
|
|
43
52
|
}
|
|
44
53
|
/**
|
|
45
54
|
* Register the @fastify/swagger plugin in the Http server.
|
|
46
55
|
*/
|
|
47
56
|
async registerSwagger() {
|
|
57
|
+
if (Config.is('http.swagger.enabled', false)) {
|
|
58
|
+
debug('Not able to register swagger plugin. Set the http.swagger.enabled configuration as true.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
48
61
|
if (swaggerPlugin) {
|
|
49
62
|
debug('Not able to register swagger plugin. Install @fastify/swagger package.');
|
|
50
63
|
await Server.plugin(swaggerPlugin, Config.get('http.swagger.configurations'));
|
|
@@ -58,17 +71,26 @@ export class HttpKernel {
|
|
|
58
71
|
* Register the @fastify/rate-limit plugin in the Http server.
|
|
59
72
|
*/
|
|
60
73
|
async registerRateLimit() {
|
|
74
|
+
if (Config.is('http.rateLimit.enabled', false)) {
|
|
75
|
+
debug('Not able to register rate limit plugin. Set the http.rateLimit.enabled configuration as true.');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
61
78
|
if (!rateLimitPlugin) {
|
|
62
79
|
debug('Not able to register rate limit plugin. Install @fastify/rate-limit package.');
|
|
63
80
|
return;
|
|
64
81
|
}
|
|
65
|
-
await Server.plugin(rateLimitPlugin,
|
|
82
|
+
await Server.plugin(rateLimitPlugin, this.getConfig('http.rateLimit'));
|
|
66
83
|
}
|
|
67
84
|
/**
|
|
68
85
|
* Register the cls-rtracer plugin in the Http server.
|
|
69
86
|
*/
|
|
70
87
|
async registerRTracer(trace) {
|
|
71
88
|
if (trace === false) {
|
|
89
|
+
debug('Not able to register rTracer plugin. Set the trace option as true in your http server options.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (trace === undefined && Config.is('http.rTracer.enabled', false)) {
|
|
93
|
+
debug('Not able to register rTracer plugin. Set the http.rTracer.enabled configuration as true.');
|
|
72
94
|
return;
|
|
73
95
|
}
|
|
74
96
|
if (!rTracerPlugin) {
|
|
@@ -76,14 +98,13 @@ export class HttpKernel {
|
|
|
76
98
|
return;
|
|
77
99
|
}
|
|
78
100
|
Server.middleware(async (ctx) => (ctx.data.traceId = rTracerPlugin.id()));
|
|
79
|
-
await Server.plugin(rTracerPlugin.fastifyPlugin,
|
|
101
|
+
await Server.plugin(rTracerPlugin.fastifyPlugin, this.getConfig('http.rTracer'));
|
|
80
102
|
}
|
|
81
103
|
/**
|
|
82
104
|
* Register the global log terminator in the Http server.
|
|
83
105
|
*/
|
|
84
106
|
async registerLoggerTerminator() {
|
|
85
|
-
if (
|
|
86
|
-
Config.is('http.logger.enabled', false)) {
|
|
107
|
+
if (Config.is('http.logger.enabled', false)) {
|
|
87
108
|
debug('Not able to register http request logger. Enable it in your http.logger.enabled configuration.');
|
|
88
109
|
return;
|
|
89
110
|
}
|
|
@@ -97,13 +118,11 @@ export class HttpKernel {
|
|
|
97
118
|
const controllers = Config.get('rc.controllers', []);
|
|
98
119
|
await Exec.concurrently(controllers, async (path) => {
|
|
99
120
|
const Controller = await this.resolvePath(path);
|
|
100
|
-
if (
|
|
101
|
-
|
|
121
|
+
if (Annotation.isAnnotated(Controller)) {
|
|
122
|
+
this.registerUsingMeta(Controller);
|
|
102
123
|
return;
|
|
103
124
|
}
|
|
104
|
-
|
|
105
|
-
const alias = `App/Http/Controllers/${Controller.name}`;
|
|
106
|
-
ioc.bind(alias, Controller, createCamelAlias);
|
|
125
|
+
ioc.transient(`App/Http/Controllers/${Controller.name}`, Controller);
|
|
107
126
|
});
|
|
108
127
|
}
|
|
109
128
|
/**
|
|
@@ -112,30 +131,34 @@ export class HttpKernel {
|
|
|
112
131
|
* and "rc.globalMiddlewares" exists.
|
|
113
132
|
*/
|
|
114
133
|
async registerMiddlewares() {
|
|
134
|
+
const middlewares = Config.get('rc.middlewares', []);
|
|
135
|
+
await Exec.concurrently(middlewares, async (path) => {
|
|
136
|
+
const Middleware = await this.resolvePath(path);
|
|
137
|
+
if (Annotation.isAnnotated(Middleware)) {
|
|
138
|
+
this.registerUsingMeta(Middleware);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const alias = `App/Http/Middlewares/${Middleware.name}`;
|
|
142
|
+
const namedAlias = `App/Http/Middlewares/Names/${String.toCamelCase(Middleware.name)}`;
|
|
143
|
+
ioc.transient(alias, Middleware).alias(namedAlias, alias);
|
|
144
|
+
});
|
|
115
145
|
await this.registerNamedMiddlewares();
|
|
116
146
|
await this.registerGlobalMiddlewares();
|
|
117
|
-
if (Config.exists('rc.middlewares')) {
|
|
118
|
-
await Exec.concurrently(Config.get('rc.middlewares'), this.resolvePath);
|
|
119
|
-
}
|
|
120
147
|
}
|
|
121
148
|
/**
|
|
122
149
|
* Register all the named middlewares found inside "rc.namedMiddlewares"
|
|
123
150
|
* property.
|
|
124
151
|
*/
|
|
125
152
|
async registerNamedMiddlewares() {
|
|
126
|
-
const namedMiddlewares = Config.get('rc.namedMiddlewares');
|
|
127
|
-
if (Is.Empty(namedMiddlewares)) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
153
|
+
const namedMiddlewares = Config.get('rc.namedMiddlewares', {});
|
|
130
154
|
await Exec.concurrently(Object.keys(namedMiddlewares), async (key) => {
|
|
131
155
|
const Middleware = await this.resolvePath(namedMiddlewares[key]);
|
|
132
|
-
if (
|
|
133
|
-
|
|
156
|
+
if (Annotation.isAnnotated(Middleware)) {
|
|
157
|
+
this.registerUsingMeta(Middleware);
|
|
134
158
|
return;
|
|
135
159
|
}
|
|
136
|
-
const createCamelAlias = false;
|
|
137
160
|
const { alias, namedAlias } = this.getNamedMiddlewareAlias(key, Middleware);
|
|
138
|
-
ioc.bind(alias, Middleware
|
|
161
|
+
ioc.bind(alias, Middleware).alias(namedAlias, alias);
|
|
139
162
|
});
|
|
140
163
|
}
|
|
141
164
|
/**
|
|
@@ -143,20 +166,19 @@ export class HttpKernel {
|
|
|
143
166
|
* property.
|
|
144
167
|
*/
|
|
145
168
|
async registerGlobalMiddlewares() {
|
|
146
|
-
const globalMiddlewares = Config.get('rc.globalMiddlewares');
|
|
147
|
-
if (Is.Empty(globalMiddlewares)) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
169
|
+
const globalMiddlewares = Config.get('rc.globalMiddlewares', []);
|
|
150
170
|
await Exec.concurrently(globalMiddlewares, async (path) => {
|
|
151
171
|
const Middleware = await this.resolvePath(path);
|
|
152
|
-
if (
|
|
153
|
-
|
|
172
|
+
if (Annotation.isAnnotated(Middleware)) {
|
|
173
|
+
this.registerUsingMeta(Middleware);
|
|
154
174
|
return;
|
|
155
175
|
}
|
|
156
|
-
const createCamelAlias = false;
|
|
157
176
|
const { alias, handler, serverMethod } = this.getGlobalMiddlewareAliasAndHandler(Middleware);
|
|
158
|
-
ioc.bind(alias, Middleware
|
|
159
|
-
Server[serverMethod](
|
|
177
|
+
ioc.bind(alias, Middleware);
|
|
178
|
+
Server[serverMethod]((...args) => {
|
|
179
|
+
const mid = ioc.safeUse(alias);
|
|
180
|
+
return mid[handler].bind(mid)(...args);
|
|
181
|
+
});
|
|
160
182
|
});
|
|
161
183
|
}
|
|
162
184
|
/**
|
|
@@ -248,4 +270,36 @@ export class HttpKernel {
|
|
|
248
270
|
resolvePath(path) {
|
|
249
271
|
return Module.resolve(`${path}?version=${Math.random()}`, Config.get('rc.meta'));
|
|
250
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Register the controllers using the meta information
|
|
275
|
+
* defined by annotations.
|
|
276
|
+
*/
|
|
277
|
+
registerUsingMeta(target) {
|
|
278
|
+
const meta = Annotation.getMeta(target);
|
|
279
|
+
ioc[meta.type](meta.alias, target);
|
|
280
|
+
if (meta.name && !meta.isGlobal) {
|
|
281
|
+
ioc.alias(meta.name, meta.alias);
|
|
282
|
+
}
|
|
283
|
+
if (meta.camelAlias) {
|
|
284
|
+
ioc.alias(meta.camelAlias, meta.alias);
|
|
285
|
+
}
|
|
286
|
+
if (meta.isGlobal) {
|
|
287
|
+
const { handler, serverMethod } = this.getGlobalMiddlewareAliasAndHandler(target);
|
|
288
|
+
Server[serverMethod]((...args) => {
|
|
289
|
+
const mid = ioc.safeUse(meta.alias);
|
|
290
|
+
return mid[handler].bind(mid)(...args);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return meta;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Get the configuration for the given key.
|
|
297
|
+
*/
|
|
298
|
+
getConfig(key) {
|
|
299
|
+
const config = Config.get(key);
|
|
300
|
+
if (Config.exists(`${key}.enabled`)) {
|
|
301
|
+
delete config.enabled;
|
|
302
|
+
}
|
|
303
|
+
return config;
|
|
304
|
+
}
|
|
251
305
|
}
|
|
@@ -10,6 +10,6 @@ import { Router } from '#src/router/Router';
|
|
|
10
10
|
import { ServiceProvider } from '@athenna/ioc';
|
|
11
11
|
export class HttpRouteProvider extends ServiceProvider {
|
|
12
12
|
register() {
|
|
13
|
-
this.container.
|
|
13
|
+
this.container.singleton('Athenna/Core/HttpRoute', Router);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -10,7 +10,7 @@ import { ServiceProvider } from '@athenna/ioc';
|
|
|
10
10
|
import { ServerImpl } from '#src/server/ServerImpl';
|
|
11
11
|
export class HttpServerProvider extends ServiceProvider {
|
|
12
12
|
register() {
|
|
13
|
-
this.container.instance('Athenna/Core/HttpServer', new ServerImpl()
|
|
13
|
+
this.container.instance('Athenna/Core/HttpServer', new ServerImpl());
|
|
14
14
|
}
|
|
15
15
|
async shutdown() {
|
|
16
16
|
const Server = this.container.use('Athenna/Core/HttpServer');
|
package/src/router/Route.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Is, Route as RouteHelper } from '@athenna/common';
|
|
10
10
|
import { UndefinedMethodException } from '#src/exceptions/UndefinedMethodException';
|
|
11
|
+
import { NotFoundMiddlewareException } from '#src/exceptions/NotFoundMiddlewareException';
|
|
11
12
|
export class Route {
|
|
12
13
|
constructor(url, methods, handler) {
|
|
13
14
|
this.route = {
|
|
@@ -28,7 +29,13 @@ export class Route {
|
|
|
28
29
|
if (!dependency[method]) {
|
|
29
30
|
throw new UndefinedMethodException(method, controller);
|
|
30
31
|
}
|
|
31
|
-
this.route.handler =
|
|
32
|
+
this.route.handler = (...args) => {
|
|
33
|
+
const service = ioc.safeUse(`App/Http/Controllers/${controller}`);
|
|
34
|
+
if (!service[method]) {
|
|
35
|
+
throw new UndefinedMethodException(method, controller);
|
|
36
|
+
}
|
|
37
|
+
return service[method].bind(dependency)(...args);
|
|
38
|
+
};
|
|
32
39
|
}
|
|
33
40
|
else {
|
|
34
41
|
this.route.handler = handler;
|
|
@@ -81,9 +88,15 @@ export class Route {
|
|
|
81
88
|
middleware(middleware, prepend = false) {
|
|
82
89
|
const insertionType = prepend ? 'unshift' : 'push';
|
|
83
90
|
if (Is.String(middleware)) {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
const namedAlias = `App/Http/Middlewares/Names/${middleware}`;
|
|
92
|
+
const alias = `App/Http/Middlewares/${middleware}`;
|
|
93
|
+
if (!ioc.has(namedAlias) && !ioc.has(alias)) {
|
|
94
|
+
throw new NotFoundMiddlewareException(alias, namedAlias);
|
|
95
|
+
}
|
|
96
|
+
this.route.middlewares.middlewares[insertionType]((...args) => {
|
|
97
|
+
const mid = ioc.use(namedAlias) || ioc.safeUse(alias);
|
|
98
|
+
return mid.handle.bind(mid)(...args);
|
|
99
|
+
});
|
|
87
100
|
return this;
|
|
88
101
|
}
|
|
89
102
|
if (Is.Function(middleware)) {
|
|
@@ -100,9 +113,15 @@ export class Route {
|
|
|
100
113
|
interceptor(interceptor, prepend = false) {
|
|
101
114
|
const insertionType = prepend ? 'unshift' : 'push';
|
|
102
115
|
if (Is.String(interceptor)) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
const namedAlias = `App/Http/Interceptors/Names/${interceptor}`;
|
|
117
|
+
const alias = `App/Http/Interceptors/${interceptor}`;
|
|
118
|
+
if (!ioc.has(namedAlias) && !ioc.has(alias)) {
|
|
119
|
+
throw new NotFoundMiddlewareException(alias, namedAlias);
|
|
120
|
+
}
|
|
121
|
+
this.route.middlewares.interceptors[insertionType]((...args) => {
|
|
122
|
+
const mid = ioc.use(namedAlias) || ioc.safeUse(alias);
|
|
123
|
+
return mid.intercept.bind(mid)(...args);
|
|
124
|
+
});
|
|
106
125
|
return this;
|
|
107
126
|
}
|
|
108
127
|
if (Is.Function(interceptor)) {
|
|
@@ -119,9 +138,15 @@ export class Route {
|
|
|
119
138
|
terminator(terminator, prepend = false) {
|
|
120
139
|
const insertionType = prepend ? 'unshift' : 'push';
|
|
121
140
|
if (Is.String(terminator)) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
const namedAlias = `App/Http/Terminators/Names/${terminator}`;
|
|
142
|
+
const alias = `App/Http/Terminators/${terminator}`;
|
|
143
|
+
if (!ioc.has(namedAlias) && !ioc.has(alias)) {
|
|
144
|
+
throw new NotFoundMiddlewareException(alias, namedAlias);
|
|
145
|
+
}
|
|
146
|
+
this.route.middlewares.terminators[insertionType]((...args) => {
|
|
147
|
+
const mid = ioc.use(namedAlias) || ioc.safeUse(alias);
|
|
148
|
+
return mid.terminate.bind(mid)(...args);
|
|
149
|
+
});
|
|
125
150
|
return this;
|
|
126
151
|
}
|
|
127
152
|
if (Is.Function(terminator)) {
|
|
@@ -8,18 +8,26 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export type ControllerOptions = {
|
|
10
10
|
/**
|
|
11
|
-
* The alias that will be used to register the
|
|
12
|
-
* the service
|
|
13
|
-
* the alias set here.
|
|
11
|
+
* The alias that will be used to register the controller inside
|
|
12
|
+
* the service container.
|
|
14
13
|
*
|
|
15
14
|
* @default App/Http/Controllers/YourControllerClassName
|
|
16
15
|
*/
|
|
17
16
|
alias?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The camel alias that will be used as an alias of the real
|
|
19
|
+
* controller alias. Camel alias is important when you want to
|
|
20
|
+
* work with constructor injection. By default, Athenna doesn't
|
|
21
|
+
* create camel alias for controllers.
|
|
22
|
+
*
|
|
23
|
+
* @default undefined
|
|
24
|
+
*/
|
|
25
|
+
camelAlias?: string;
|
|
18
26
|
/**
|
|
19
27
|
* The registration type that will be used to register your controller
|
|
20
|
-
* inside the service
|
|
28
|
+
* inside the service container.
|
|
21
29
|
*
|
|
22
|
-
* @default transient
|
|
30
|
+
* @default 'transient'
|
|
23
31
|
*/
|
|
24
32
|
type?: 'fake' | 'scoped' | 'singleton' | 'transient';
|
|
25
33
|
};
|
|
@@ -8,18 +8,26 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export type MiddlewareOptions = {
|
|
10
10
|
/**
|
|
11
|
-
* The alias that will be used to register the
|
|
12
|
-
* the service
|
|
13
|
-
* the alias set here.
|
|
11
|
+
* The alias that will be used to register the middleware inside
|
|
12
|
+
* the service container.
|
|
14
13
|
*
|
|
15
14
|
* @default App/Http/Middlewares/YourMiddlewareClassName
|
|
16
15
|
*/
|
|
17
16
|
alias?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The camel alias that will be used as an alias of the real
|
|
19
|
+
* middleware alias. Camel alias is important when you want to
|
|
20
|
+
* work with constructor injection. By default, Athenna doesn't
|
|
21
|
+
* create camel alias for middlewares.
|
|
22
|
+
*
|
|
23
|
+
* @default undefined
|
|
24
|
+
*/
|
|
25
|
+
camelAlias?: string;
|
|
18
26
|
/**
|
|
19
27
|
* The registration type that will be used to register your middleware
|
|
20
|
-
* inside the service
|
|
28
|
+
* inside the service container.
|
|
21
29
|
*
|
|
22
|
-
* @default transient
|
|
30
|
+
* @default 'transient'
|
|
23
31
|
*/
|
|
24
32
|
type?: 'fake' | 'scoped' | 'singleton' | 'transient';
|
|
25
33
|
/**
|
|
@@ -34,7 +42,7 @@ export type MiddlewareOptions = {
|
|
|
34
42
|
* is true, Athenna will ignore this property. Athenna will always set the default
|
|
35
43
|
* name of your middleware as the middleware class name in camel case format.
|
|
36
44
|
*
|
|
37
|
-
* @default yourMiddlewareClassName
|
|
45
|
+
* @default 'yourMiddlewareClassName'
|
|
38
46
|
*/
|
|
39
47
|
name?: string;
|
|
40
48
|
};
|