Skip to content
This repository has been archived by the owner on May 8, 2020. It is now read-only.

Commit

Permalink
feat(routing): implemented basic routing with decorators and separate…
Browse files Browse the repository at this point in the history
…d demo out of core logic for later extraction
  • Loading branch information
zakhenry committed May 23, 2016
1 parent b1620ac commit 49e937a
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 89 deletions.
3 changes: 3 additions & 0 deletions _demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Notice
This directory need to be extracted out to ubiquits/ubiquits as a proper
framework demo once the build toolchain is worked out.
5 changes: 5 additions & 0 deletions _demo/api/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { server } from './main';

server.start().then(() => {
console.log('Server running at:', server.getEngine().info.uri);
});
2 changes: 2 additions & 0 deletions _demo/api/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {TestController} from './test.controller';
export {SimpleController} from './simple.controller';
20 changes: 20 additions & 0 deletions _demo/api/controllers/simple.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { Server } from '../../../api/servers/abstract.server';
import { AbstractController } from '../../../api/controllers/abstract.controller';
import { RouteBase } from '../../../api/controllers/routeBase.decorator';
import { Action } from '../../../api/controllers/action.decorator';

@Injectable()
@RouteBase('simple')
export class SimpleController extends AbstractController {

constructor(server: Server) {
super(server);
}

@Action('GET', '/test/{id}')
public test() {
return 'hello world';
}

}
File renamed without changes.
16 changes: 16 additions & 0 deletions _demo/api/controllers/test.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Server } from '../../../api/servers/abstract.server';
import { AbstractController } from '../../../api/controllers/abstract.controller';
import { RouteBase } from '../../../api/controllers/routeBase.decorator';

@Injectable()
@RouteBase('test')
export class TestController extends AbstractController {

constructor(server: Server) {
super(server);

console.log('route base is ', this.routeBase);
}

}
20 changes: 20 additions & 0 deletions _demo/api/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { coreInjector } from '../../api/main';
import { ReflectiveInjector, ResolvedReflectiveProvider } from '@angular/core';
import { Server } from '../../api/servers/abstract.server';
import * as Controllers from './controllers';
import * as _ from 'lodash';

// console.log('typeof ControllerMap', typeof ControllerMap);

// const controllers = ControllerMap.values();

let resolvedProviders = ReflectiveInjector.resolve(_.values(Controllers));

let injector = ReflectiveInjector.fromResolvedProviders(resolvedProviders, coreInjector);

export const server: Server = injector.get(Server);

resolvedProviders.forEach((resolvedControllerProvider: ResolvedReflectiveProvider) => {
console.log('initializing', resolvedControllerProvider.key);
injector.instantiateResolved(resolvedControllerProvider);
});
9 changes: 0 additions & 9 deletions api/bootstrap.ts

This file was deleted.

79 changes: 79 additions & 0 deletions api/controllers/abstract.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Server } from '../servers/abstract.server';
import { Injectable } from '@angular/core';
import { Request as HapiRequest, IReply, Response } from 'hapi';
import * as _ from 'lodash';
import { Cat } from '../../common/models/index';
import { Action } from './action.decorator';

export interface Request extends HapiRequest {

}

export interface RouteParam {
key: string;
value: string;
}

export type ActionType = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';

export interface MethodDefinition {
method: ActionType;
route: string;
}

export interface MethodDictionary {
[methodSignature: string]: MethodDefinition;
}

@Injectable()
export abstract class AbstractController {

protected __actionMethods: Map<string, MethodDefinition>;

protected routeBase: string;

constructor(protected server: Server) {
this.registerRoutes();
}

public registerActionMethod(methodSignature: string, method: ActionType, route: string) {
if (!this.__actionMethods) {
this.__actionMethods = new Map<string, MethodDefinition>();
}

const methodDefinition: MethodDefinition = {
method,
route
};

this.__actionMethods.set(methodSignature, methodDefinition);
}

@Action('GET', '/{id}')
public getOne(request: Request, ...routeParams: RouteParam[]) {

const greeting = new Cat().greet();

return {id: routeParams[0], greeting};
}

public registerRoutes(): void {

this.__actionMethods.forEach((methodDefinition: MethodDefinition, methodSignature: string) => {

this.server.register({
method: methodDefinition.method,
path: `/${this.routeBase}${methodDefinition.route}`,
handler: (request: Request, reply: IReply): Response => {

let response = this[methodSignature](request, ...request.paramsArray);

return reply(response);
}
});

});

}

}
8 changes: 8 additions & 0 deletions api/controllers/action.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ActionType } from './abstract.controller';
export function Action(method: ActionType, route: string) {

return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {

target.registerActionMethod(propertyKey, method, route);
};
}
12 changes: 12 additions & 0 deletions api/controllers/routeBase.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function RouteBase(base: string) {

console.log('decorating!');

return function (target: Function) {

(<any>target).prototype.routeBase = base;

// Reflect.defineMetadata('RouteBase', base, target);

};
}
13 changes: 6 additions & 7 deletions api/main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'es6-shim';
import 'reflect-metadata';
import { ReflectiveInjector, provide } from '@angular/core';
import { Server, HapiServer } from './server';
import { TestController } from './test';
let injector = ReflectiveInjector.resolveAndCreate([
TestController,
import { Server } from './servers/abstract.server';
import { HapiServer } from './servers/hapi.server';
import { AbstractController } from './controllers/abstract.controller';

export const coreInjector = ReflectiveInjector.resolveAndCreate([
AbstractController,
provide(Server, {useClass: HapiServer}),
]);

export const server: HapiServer = injector.get(Server);

injector.get(TestController);
34 changes: 0 additions & 34 deletions api/server.ts

This file was deleted.

21 changes: 21 additions & 0 deletions api/servers/abstract.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IRouteConfiguration } from 'hapi';

export abstract class Server {

constructor() {
this.initialize();
}

protected server: any;

public abstract register(config: IRouteConfiguration): void;

protected abstract initialize(): this;

public abstract start(): Promise<this>;

public getEngine(): any {
return this.server;
}

}
24 changes: 24 additions & 0 deletions api/servers/hapi.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Server as Hapi, IRouteConfiguration } from 'hapi';
import { Server } from './abstract.server';

export class HapiServer extends Server {

protected initialize() {
this.server = new Hapi();

this.server.connection({
host: 'localhost',
port: 3000
});
return this;
}

public register(config: IRouteConfiguration): void {
return this.server.route(config);
}

public start(): Promise<this> {
return this.server.start().then(() => this);
}

}
29 changes: 0 additions & 29 deletions api/test.ts

This file was deleted.

4 changes: 3 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ var path = require('path');
// /* Variables */
let tsProject = tsc.createProject('./tsconfig.api.json');
let sourceFiles = [
'./_demo/api/**/*.ts',
'./api/**/*.ts',
'./common/**/*.ts',
'./typings/**/*.d.ts',
'!./typings/index.d.ts',
'!./typings/**/es6-shim/*.d.ts',
];
let testFiles = ['./api/**/*.spec.ts'];
let testFiles = ['./api/**/*.spec.ts', './_demo/api/**/*.spec.ts'];
let outDir = require('./tsconfig.api.json').compilerOptions.outDir;
let entryPoint = './localhost.js';

Expand Down Expand Up @@ -172,6 +173,7 @@ gulp.task('nodemon', ['build'], () => {
'ext': 'js json ts',
watch: [
'api',
'_demo',
'common'
],
nodeArgs: [
Expand Down
12 changes: 4 additions & 8 deletions localhost.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const API = require('./build/api/api/main.js');
const API = require('./build/api/_demo/api/main.js');
const server = API.server;

const WebpackPlugin = require('hapi-webpack-plugin');
Expand All @@ -23,15 +23,11 @@ const hot = {
/**
* Register plugin and start server
*/
server.getHapi().register({
server.getEngine().register({
register: WebpackPlugin,
options: {compiler, assets, hot}
});

server.start((err) => {

if (err) {
throw err;
}
console.log('Server running at:', server.getHapi().info.uri);
server.start().then(() => {
console.log('Server running at:', server.getEngine().info.uri);
});
1 change: 0 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"no-eval": true,
"no-arg": true,
"no-internal-module": true,
"no-trailing-whitespace": true,
"no-bitwise": true,
"no-shadowed-variable": true,
"no-unused-expression": true,
Expand Down

0 comments on commit 49e937a

Please sign in to comment.