@athenna/http 4.6.0 → 4.7.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@athenna/http",
3
- "version": "4.6.0",
3
+ "version": "4.7.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>",
@@ -67,16 +67,16 @@
67
67
  "#tests": "./tests/index.js"
68
68
  },
69
69
  "dependencies": {
70
- "fastify": "^4.21.0"
70
+ "fastify": "^4.22.0"
71
71
  },
72
72
  "devDependencies": {
73
- "@athenna/artisan": "^4.9.0",
73
+ "@athenna/artisan": "^4.10.0",
74
74
  "@athenna/common": "^4.10.1",
75
75
  "@athenna/config": "^4.4.0",
76
- "@athenna/ioc": "^4.2.0",
77
- "@athenna/logger": "^4.3.0",
78
- "@athenna/test": "^4.5.0",
79
- "@athenna/view": "^4.2.0",
76
+ "@athenna/ioc": "^4.4.0",
77
+ "@athenna/logger": "^4.4.0",
78
+ "@athenna/test": "^4.7.0",
79
+ "@athenna/view": "^4.3.0",
80
80
  "@fastify/cors": "^8.1.1",
81
81
  "@fastify/helmet": "^10.0.2",
82
82
  "@fastify/rate-limit": "^7.5.0",
@@ -209,30 +209,27 @@
209
209
  "providers": [],
210
210
  "controllers": [
211
211
  "#tests/fixtures/controllers/HelloController",
212
- "#tests/fixtures/controllers/DecoratedController"
212
+ "#tests/fixtures/controllers/AnnotatedController"
213
213
  ],
214
214
  "middlewares": [
215
- "#tests/fixtures/middlewares/Middleware",
216
- "#tests/fixtures/middlewares/ImportedMiddleware",
217
- "#tests/fixtures/middlewares/DecoratedMiddleware",
218
- "#tests/fixtures/middlewares/DecoratedInterceptor",
219
- "#tests/fixtures/middlewares/DecoratedTerminator"
215
+ "#tests/fixtures/middlewares/MyMiddleware",
216
+ "#tests/fixtures/middlewares/ImportedMiddleware"
220
217
  ],
221
218
  "namedMiddlewares": {
222
- "middleware": "#tests/fixtures/middlewares/Middleware",
223
- "interceptor": "#tests/fixtures/middlewares/Interceptor",
224
- "terminator": "#tests/fixtures/middlewares/Terminator",
225
- "not-found-middleware": "#tests/fixtures/middlewares/DecoratedMiddleware",
226
- "not-found-interceptor": "#tests/fixtures/middlewares/DecoratedInterceptor",
227
- "not-found-terminator": "#tests/fixtures/middlewares/DecoratedTerminator"
219
+ "myMiddleware": "#tests/fixtures/middlewares/MyMiddleware",
220
+ "myInterceptor": "#tests/fixtures/middlewares/MyInterceptor",
221
+ "myTerminator": "#tests/fixtures/middlewares/MyTerminator",
222
+ "not-found-middleware": "#tests/fixtures/middlewares/AnnotatedMiddleware",
223
+ "not-found-interceptor": "#tests/fixtures/middlewares/AnnotatedInterceptor",
224
+ "not-found-terminator": "#tests/fixtures/middlewares/AnnotatedTerminator"
228
225
  },
229
226
  "globalMiddlewares": [
230
- "#tests/fixtures/middlewares/Middleware",
231
- "#tests/fixtures/middlewares/Interceptor",
232
- "#tests/fixtures/middlewares/Terminator",
233
- "#tests/fixtures/middlewares/DecoratedGlobalMiddleware",
234
- "#tests/fixtures/middlewares/DecoratedGlobalInterceptor",
235
- "#tests/fixtures/middlewares/DecoratedGlobalTerminator"
227
+ "#tests/fixtures/middlewares/MyMiddleware",
228
+ "#tests/fixtures/middlewares/MyInterceptor",
229
+ "#tests/fixtures/middlewares/MyTerminator",
230
+ "#tests/fixtures/middlewares/AnnotatedGlobalMiddleware",
231
+ "#tests/fixtures/middlewares/AnnotatedGlobalInterceptor",
232
+ "#tests/fixtures/middlewares/AnnotatedGlobalTerminator"
236
233
  ],
237
234
  "commands": {
238
235
  "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
- const alias = options.alias;
22
- const createCamelAlias = false;
23
- if (ioc.hasDependency(alias)) {
24
- debug('Controller %s was already registered in the service container. Skipping registration via Controller annotation.', alias);
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
- ioc[options.type](alias, target, createCamelAlias);
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 { Server } from '#src/facades/Server';
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
- name: String.toCamelCase(target.name),
20
+ type: 'transient',
21
21
  alias: `App/Http/Interceptors/${target.name}`,
22
- type: 'transient'
22
+ name: String.toCamelCase(target.name)
23
23
  });
24
- const alias = options.alias;
25
- const createCamelAlias = false;
26
- if (ioc.hasDependency(alias)) {
27
- debug('Interceptor %s was already registered in the service container. Skipping registration via Interceptor annotation.', alias);
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[options.type](alias, target, createCamelAlias);
31
- Reflect.defineMetadata('ioc:registered', true, target);
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
- const Interceptor = ioc.safeUse(alias);
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 { Server } from '#src/facades/Server';
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
- name: String.toCamelCase(target.name),
20
+ type: 'transient',
21
21
  alias: `App/Http/Middlewares/${target.name}`,
22
- type: 'transient'
22
+ name: String.toCamelCase(target.name)
23
23
  });
24
- const alias = options.alias;
25
- const createCamelAlias = false;
26
- if (ioc.hasDependency(alias)) {
27
- debug('Middleware %s was already registered in the service container. Skipping registration via Middleware annotation.', alias);
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[options.type](alias, target, createCamelAlias);
31
- Reflect.defineMetadata('ioc:registered', true, target);
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
- const Middleware = ioc.safeUse(alias);
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 { Server } from '#src/facades/Server';
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
- name: String.toCamelCase(target.name),
20
+ type: 'transient',
21
21
  alias: `App/Http/Terminators/${target.name}`,
22
- type: 'transient'
22
+ name: String.toCamelCase(target.name)
23
23
  });
24
- const alias = options.alias;
25
- const createCamelAlias = false;
26
- if (ioc.hasDependency(alias)) {
27
- debug('Terminator %s was already registered in the service container. Skipping registration via Terminator annotation.', alias);
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[options.type](alias, target, createCamelAlias);
31
- Reflect.defineMetadata('ioc:registered', true, target);
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
- const Terminator = ioc.safeUse(alias);
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 { File, Exec, Is, Module } from '@athenna/common';
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, Config.get('http.cors'));
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, Config.get('http.helmet'));
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, Config.get('http.rateLimit'));
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, Config.get('http.rTracer'));
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 (!Config.exists('http.logger.enabled') ||
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 (Reflect.hasMetadata('ioc:registered', Controller)) {
101
- debug('Controller %s already registered by Controller annotation. Skipping registration via HttpKernel.', Controller.name);
121
+ if (Annotation.isAnnotated(Controller)) {
122
+ this.registerUsingMeta(Controller);
102
123
  return;
103
124
  }
104
- const createCamelAlias = false;
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 (Reflect.hasMetadata('ioc:registered', Middleware)) {
133
- debug('Named middleware %s already registered by Middleware annotation. Skipping registration via HttpKernel.', Middleware.name);
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, createCamelAlias).alias(namedAlias, alias);
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 (Reflect.hasMetadata('ioc:registered', Middleware)) {
153
- debug('Global middleware %s already registered by Middleware annotation. Skipping registration via HttpKernel.', Middleware.name);
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, createCamelAlias);
159
- Server[serverMethod](ioc.safeUse(alias)[handler]);
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.instance('Athenna/Core/HttpRoute', new Router(), false);
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(), false);
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');
@@ -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 = dependency[method].bind(dependency);
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 mid = ioc.use(`App/Http/Middlewares/Names/${middleware}`) ||
85
- ioc.safeUse(`App/Http/Middlewares/${middleware}`);
86
- this.route.middlewares.middlewares[insertionType](mid.handle.bind(mid));
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 inte = ioc.use(`App/Http/Interceptors/Names/${interceptor}`) ||
104
- ioc.safeUse(`App/Http/Interceptors/${interceptor}`);
105
- this.route.middlewares.interceptors[insertionType](inte.intercept.bind(inte));
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 ter = ioc.use(`App/Http/Terminators/Names/${terminator}`) ||
123
- ioc.safeUse(`App/Http/Terminators/${terminator}`);
124
- this.route.middlewares.terminators[insertionType](ter.terminate.bind(ter));
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 dependency inside
12
- * the service provider. Athenna will not create camel alias from
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 provider.
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 dependency inside
12
- * the service provider. Athenna will not create camel alias from
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 provider.
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
  };