Skip to content

Commit

Permalink
Merge pull request #17 from kitesjs/dev-middleware
Browse files Browse the repository at this point in the history
Support rest api middleware
  • Loading branch information
vunb authored Aug 1, 2019
2 parents 5b6ccee + d88d03f commit a1b7c37
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions packages/common/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './core';
export * from './extension';
export * from './http';
export * from './decorate';
5 changes: 3 additions & 2 deletions packages/core/engine/kites-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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'
}
},
Expand Down
1 change: 0 additions & 1 deletion packages/core/injector/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './container';
export * from './decorate';
3 changes: 1 addition & 2 deletions packages/rest/decorators/controller.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
102 changes: 102 additions & 0 deletions packages/rest/decorators/decorators.spec.ts
Original file line number Diff line number Diff line change
@@ -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();
});
});
78 changes: 20 additions & 58 deletions packages/rest/rest.extension.ts
Original file line number Diff line number Diff line change
@@ -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
*/
Expand All @@ -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: {}
Expand All @@ -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 {
Expand All @@ -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];
Expand Down

0 comments on commit a1b7c37

Please sign in to comment.