diff --git a/packages/core/injector/decorate.ts b/packages/common/decorators/decorate.ts similarity index 95% rename from packages/core/injector/decorate.ts rename to packages/common/decorators/decorate.ts index a2fb317..300f3c9 100644 --- a/packages/core/injector/decorate.ts +++ b/packages/common/decorators/decorate.ts @@ -15,7 +15,7 @@ function _param( }; } -// Allows VanillaJS developers to use decorators: +// Allows developers to use decorators: // decorate(injectable("Foo", "Bar"), FooBar); // decorate(targetName("foo", "bar"), FooBar); // decorate(named("foo"), FooBar, 0); diff --git a/packages/common/decorators/index.ts b/packages/common/decorators/index.ts index c53be37..59db613 100644 --- a/packages/common/decorators/index.ts +++ b/packages/common/decorators/index.ts @@ -1,3 +1,4 @@ export * from './core'; export * from './extension'; export * from './http'; +export * from './decorate'; diff --git a/packages/core/engine/kites-instance.ts b/packages/core/engine/kites-instance.ts index 57b0350..5c12d08 100644 --- a/packages/core/engine/kites-instance.ts +++ b/packages/core/engine/kites-instance.ts @@ -109,7 +109,8 @@ export class KitesInstance extends EventEmitter implements IKites { } get defaults() { - let parent = module.parent || module; + const parent = module.parent || module; + const defaultLevel = process.env.NODE_ENV === 'production' ? 'info' : 'debug'; return { appDirectory: appRoot.toString(), // TODO: separate kites discover as an api @@ -120,7 +121,7 @@ export class KitesInstance extends EventEmitter implements IKites { env: process.env.NODE_ENV || 'development', logger: { console: { - level: 'debug', + level: defaultLevel, transport: 'console' } }, diff --git a/packages/core/injector/index.ts b/packages/core/injector/index.ts index b0b7485..85ee15b 100644 --- a/packages/core/injector/index.ts +++ b/packages/core/injector/index.ts @@ -1,2 +1 @@ export * from './container'; -export * from './decorate'; diff --git a/packages/rest/decorators/controller.decorator.ts b/packages/rest/decorators/controller.decorator.ts index 9ba20d5..41d0fb0 100644 --- a/packages/rest/decorators/controller.decorator.ts +++ b/packages/rest/decorators/controller.decorator.ts @@ -2,8 +2,7 @@ import { METADATA_KEY } from '../constants'; import { ControllerMetadata } from '../interfaces/controller-metadata.interface'; import { Middleware } from '../interfaces/middleware.interface'; -import { Injectable } from '@kites/common'; -import { Decorate } from '@kites/core'; +import { Decorate, Injectable } from '@kites/common'; function Controller(path: string, ...middleware: Middleware[]) { return function (target: any) { diff --git a/packages/rest/decorators/decorators.spec.ts b/packages/rest/decorators/decorators.spec.ts new file mode 100644 index 0000000..eaa9e83 --- /dev/null +++ b/packages/rest/decorators/decorators.spec.ts @@ -0,0 +1,102 @@ +import { METADATA_KEY, PARAMETER_TYPE } from '../constants'; +import { ControllerMetadata, ControllerMethodMetadata, ControllerParameterMetadata } from '../interfaces'; +import { Controller } from './controller.decorator'; + +import { expect } from 'chai'; +import { HttpMethod } from './http-method.controller'; +import { Params } from './http-param.decorator'; + +describe('@Controller', () => { + + it('should add controller metadata to a class when decorated with @Controller()', (done) => { + let path = 'foo'; + let middleware = [ + function () { + return; + }, + 'foo', + 'bar', + ]; + + @Controller(path, ...middleware) + class TestController { } + + let controllerMetadata: ControllerMetadata = Reflect.getMetadata( + METADATA_KEY.Controller, + TestController + ); + + expect(controllerMetadata.path).eql(path); + expect(controllerMetadata.target).eql(TestController); + expect(controllerMetadata.middleware).eql(middleware); + + done(); + }); + + it('should add method metadata to a class when decorated with @HttpMethod()', (done) => { + let path = 'foo'; + let method = 'get'; + let middleware = [ + function () { + return; + }, + 'foo', + 'bar', + ]; + + class TestController { + @HttpMethod(method, path, ...middleware) + test1() { } + + @HttpMethod('foo', 'bar') + test2() { } + + @HttpMethod('abc', 'xyz') + test3() { } + } + + let methodMetadata: ControllerMethodMetadata[] = Reflect.getMetadata( + METADATA_KEY.ControllerMethod, + TestController, + ); + + expect(methodMetadata.length).eql(3); + + let metadata = methodMetadata[0]; + expect(metadata.middleware).eql(middleware); + expect(metadata.path).eql(path); + expect(metadata.key).eql('test1'); + expect(metadata.method).eql(method); + expect(metadata.target.constructor).eql(TestController); + done(); + }); + + it('should add parameter metadata to a class when decorated with @Params()', (done) => { + + class NinjaController { + move( + @Params(PARAMETER_TYPE.PARAMS, 'distance') name: string, + @Params(PARAMETER_TYPE.PARAMS, 'steps') steps: number + ) { } + + fight( + @Params(PARAMETER_TYPE.PARAMS, 'darts') darts: number + ) { } + } + + let methodMetadataList: ControllerParameterMetadata = Reflect.getMetadata( + METADATA_KEY.ControllerParameter, + NinjaController, + ); + + expect(methodMetadataList.hasOwnProperty('move')).eql(true); + expect(methodMetadataList.move.length).eql(2); + expect(methodMetadataList.fight.length).eql(1); + + let paramDetails = methodMetadataList.move[0]; + expect(paramDetails.index).eql(0); + expect(paramDetails.parameterName).eql('distance'); + expect(paramDetails.type).eq(PARAMETER_TYPE.PARAMS); + done(); + }); +}); diff --git a/packages/rest/rest.extension.ts b/packages/rest/rest.extension.ts index ff5b60e..45c3939 100644 --- a/packages/rest/rest.extension.ts +++ b/packages/rest/rest.extension.ts @@ -1,54 +1,13 @@ import * as express from 'express'; -import { Injectable } from '@kites/common'; import { Container, ExtensionOptions, IKites, KitesExtension } from '@kites/core'; import { OutgoingHttpHeaders } from 'http'; import { PARAMETER_TYPE, TYPE } from './constants'; -import { Controller, Get } from './decorators'; -import { IController, ParameterMetadata } from './interfaces'; +import { IController, Middleware, ParameterMetadata } from './interfaces'; import { HttpResponseMessage } from './results/http-response-message'; import { GetControllerMetadata, GetControllerMethodMetadata, GetControllerParameterMetadata, GetControllersFromContainer, GetControllersFromMetadata } from './utils'; -@Injectable() -class SimpleService { - public test(): string { - return 'Hello Service!!!'; - } -} - -@Controller('/api1') -class TestController { - - constructor(public svSimple: SimpleService) { - - } - - @Get('/') test() { - return this.svSimple.test(); - } -} - -@Controller('/api2') -class Test2Controller { - - constructor(public svSimple: SimpleService) { - - } - - @Get('/') test() { - return this.svSimple.test(); - } - - @Get('/path2') test2() { - return this.svSimple.test(); - } - - @Get('/path2') test3() { - return this.svSimple.test(); - } -} - /** * Main Extension */ @@ -58,12 +17,8 @@ class RestExtension implements KitesExtension { constructor(private kites: IKites, options: ExtensionOptions) { this.name = 'Rest'; - // register system service(s) + // TODO: Support HttpContext kites.container - .addProvider({ - provide: SimpleService, - useClass: SimpleService - }) .addProvider({ provide: TYPE.HttpContext, useValue: {} @@ -82,13 +37,12 @@ class RestExtension implements KitesExtension { } + /** + * Load more works at this entry! + */ init(kites: IKites, options: ExtensionOptions) { - const service = kites.container.inject(SimpleService); - console.log('Name: ', this.name, service.test()); - - const testController = kites.container.inject(TestController); - console.log('Controller: ', testController.test()); + kites.logger.debug('Initializing extension rest ...'); } private registerControllers(container: Container): express.Router { @@ -102,31 +56,39 @@ class RestExtension implements KitesExtension { const methodMetadata = GetControllerMethodMetadata(controller.constructor); const parameterMetadata = GetControllerParameterMetadata(controller.constructor); - console.log('Controller Metadata: ', controller, controllerMetadata, methodMetadata, parameterMetadata); + this.kites.logger.debug('Register controller: ' + controller.constructor.name); if (controllerMetadata && methodMetadata) { + let controllerMiddleware = this.resolveMiddleware(...controllerMetadata.middleware); + methodMetadata.forEach(metadata => { let paramList: ParameterMetadata[] = []; if (parameterMetadata) { paramList = parameterMetadata[metadata.key] || []; } const handler = this.handlerFactory(controllerMetadata.target, metadata.key, paramList); - + const routeMiddleware = this.resolveMiddleware(...metadata.middleware); router[metadata.method]( `${controllerMetadata.path}${metadata.path}`, - // ...controllerMiddleware, - // ...routeMiddleware, + ...controllerMiddleware, + ...routeMiddleware, handler ); }); } }); - console.log('Controllers: ', constructors); - return router; } + private resolveMiddleware(...middleware: Middleware[]) + : express.RequestHandler[] { + return middleware.map((item) => { + // TODO: Implement BaseMiddleware + return item as express.RequestHandler; + }); + } + private copyHeadersTo(headers: OutgoingHttpHeaders, target: express.Response) { for (const name of Object.keys(headers)) { const headerValue = headers[name];