Skip to content

Commit

Permalink
feat(routes): Renamed @action decorator to @route
Browse files Browse the repository at this point in the history
BREAKING CHANGE: All imports and instances of @action need to be renamed to @route

Example
```
import { Action } from 'ubiquits/core/server';
[...]
@action('GET', '/test')
public method()
```

becomes
```
import { Route } from 'ubiquits/core/server';
[...]
@route('GET', '/test')
public method()
```
  • Loading branch information
zakhenry committed Jun 17, 2016
1 parent 1d345c9 commit 8054c10
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 116 deletions.
16 changes: 8 additions & 8 deletions docs/guide/controllers.md
Expand Up @@ -55,43 +55,43 @@ of methods for interacting with the resource that controller provides.

### `getOne`
```typescript
@Action('GET', '/{id}')
@Route('GET', '/:id')
getOne(request: Request, routeParams: RouteParamMap):Response;
```

### `getMany` (planned)
```typescript
@Action('GET', '/')
@Route('GET', '/')
getMany(request: Request, routeParams: RouteParamMap):Response;
```
### `postOne` (planned)
```typescript
@Action('POST', '/')
@Route('POST', '/')
postOne(request: Request, routeParams: RouteParamMap):Response;
```
### `postMany` (planned)
```typescript
@Action('POST', '/')
@Route('POST', '/')
postMany(request: Request, routeParams: RouteParamMap):Response;
```
### `putOne` (planned)
```typescript
@Action('PUT', '/{id}')
@Route('PUT', '/:id')
putOne(request: Request, routeParams: RouteParamMap):Response;
```
### `putMany` (planned)
```typescript
@Action('PUT', '/')
@Route('PUT', '/')
putMany(request: Request, routeParams: RouteParamMap):Response;
```
### `deleteOne` (planned)
```typescript
@Action('DELETE', '/{id}')
@Route('DELETE', '/:id')
deleteOne(request: Request, routeParams: RouteParamMap):Response;
```
### `deleteMany` (planned)
```typescript
@Action('DELETE', '/')
@Route('DELETE', '/')
deleteMany(request: Request, routeParams: RouteParamMap):Response;
```

2 changes: 1 addition & 1 deletion docs/guide/middleware.md
Expand Up @@ -22,7 +22,7 @@ Middleware are applied with the method decorators `@Before(...middlewareFactorie
Middleware is applied in left to right order of the decorator params.
For example:
```typescript
@Action('GET', '/example')
@Route('GET', '/example')
@Before(debugLog('Middleware ran 1'), debugLog('Middleware ran 2'))
@After(debugLog('Middleware ran 3'))
public exampleMethod(request: Request, response: Response): Response {
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Expand Up @@ -19,7 +19,7 @@ description: Full stack isomorphic typescript framework.
### Developer Preview [June 17th]
- [ ] Model hydration and mocking
- [ ] `ResourceController` implementation with CRUD routes
- [ ] Custom middleware registration
- [x] Custom middleware registration
- [ ] Post-initialization cli tour
- [ ] Full stack demo in quickstart
- [ ] FAQ page in docs
Expand All @@ -37,7 +37,7 @@ description: Full stack isomorphic typescript framework.
- [x] Full stack debug breakpoints in Webstorm
- [x] Live reloading browser
- [x] Live restarting server
- [x] Route registration with `@Action` decorator
- [x] Route registration with `@Route` decorator
- [x] `docker-compose.json` running postgres db
- [x] Connection to database from localhost with `Sequelize`
- [x] Testing framework for both frontend and backend
Expand Down
74 changes: 74 additions & 0 deletions src/server/bootstrap.ts
@@ -0,0 +1,74 @@
import 'core-js';
import 'reflect-metadata';
import {
ReflectiveInjector,
Provider,
Type,
provide,
ResolvedReflectiveProvider
} from '@angular/core';
import { Server } from './servers/abstract.server';
import { AbstractController } from './controllers/abstract.controller';
import { Logger } from '../common/services/logger.service';
import { coreInjector } from './main';
export {provide} from '@angular/core';

export type ProviderDefinition = Type | Provider | {
[k: string]: any;
} | any[];

export interface BootstrapResponse {
injector: ReflectiveInjector;
server: Server;
logger: Logger;
}

export interface ControllerDictionary<T extends AbstractController> {
[key:string]: T;
}

export function bootstrap(controllers: ControllerDictionary<any>, providers: ProviderDefinition[] = []): BootstrapResponse {

let logger: Logger;
try {

let controllerArray = Object.keys(controllers).map(key => controllers[key]);

// resolve all controllers
let resolvedControllerProviders = ReflectiveInjector.resolve(controllerArray);

// resolve all other user classes
const resolvedProviders:ResolvedReflectiveProvider[] = ReflectiveInjector.resolve(providers)
.concat(resolvedControllerProviders);

// get an injector from the resolutions, using the core injector as parent
const injector = ReflectiveInjector.fromResolvedProviders(resolvedProviders, coreInjector);

// assign logger instance as soon as possible so the error handler might use it
logger = injector.get(Logger).source('bootstrap');

// iterate over the controller providers, instantiating them to register their routes
resolvedControllerProviders.forEach((resolvedControllerProvider: ResolvedReflectiveProvider) => {
logger.info(`initializing ${resolvedControllerProvider.key.displayName}`);
injector.instantiateResolved(resolvedControllerProvider)
.registerInjector(injector)
.registerRoutes();
});

// get vars for the bootstrapper
const server: Server = injector.get(Server);

return {injector, server, logger};

} catch (e) {
if (logger){
logger.critical(e);
} else {
console.error('Failed to initialize Logger, falling back to console');
console.error(e);
}
process.exit(1);
}

}

14 changes: 0 additions & 14 deletions src/server/controllers/abstract.controller.spec.ts

This file was deleted.

12 changes: 6 additions & 6 deletions src/server/controllers/abstract.controller.ts
@@ -1,4 +1,4 @@
import { Server } from '../servers/abstract.server';
import { Server, HttpMethod } from '../servers/abstract.server';
import { Injectable, Injector } from '@angular/core';
import { Logger } from '../../common/services/logger.service';
import { InjectableMiddlewareFactory, MiddlewareFactory } from '../middleware/index';
Expand All @@ -7,10 +7,10 @@ import { Response } from './response';
import { Request } from './request';
import { initializeMiddlewareRegister } from '../middleware/middleware.decorator';

export type ActionType = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
export const httpMethods:HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];

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

Expand Down Expand Up @@ -58,13 +58,13 @@ export abstract class AbstractController {
}

/**
* Register an action. This is used by the @Action() decoratore, but can also be used directly
* Register an action. This is used by the @Route() decoratore, but can also be used directly
* for custom route registration
* @param methodSignature
* @param method
* @param route
*/
public registerActionMethod(methodSignature: string, method: ActionType, route: string): void {
public registerActionMethod(methodSignature: string, method: HttpMethod, route: string): void {
if (!this.actionMethods) {
this.actionMethods = new Map<string, MethodDefinition>();
}
Expand Down Expand Up @@ -129,7 +129,7 @@ export abstract class AbstractController {
this.server.register({
methodName: methodSignature,
method: methodDefinition.method,
path: `/api/${this.routeBase}${methodDefinition.route}`,
path: `${process.env.API_BASE}/${this.routeBase}${methodDefinition.route}`,
callStack: callStack,
callStackHandler: (request: Request, response: Response): Promise<Response> => {
return callStack.reduce((current: Promise<Response>, next: PromiseFactory<Response>): Promise<Response> => {
Expand Down
2 changes: 1 addition & 1 deletion src/server/controllers/index.ts
@@ -1,6 +1,6 @@
export * from './routeBase.decorator';
export * from './abstract.controller';
export * from './resource.controller';
export * from './action.decorator';
export * from './route.decorator';
export * from './request'
export * from './response'
6 changes: 3 additions & 3 deletions src/server/controllers/resource.controller.ts
Expand Up @@ -2,7 +2,7 @@ import { Server } from '../servers/abstract.server';
import { Injectable } from '@angular/core';
import { AbstractController} from './abstract.controller';
import { Logger } from '../../common/services/logger.service';
import { Action } from './action.decorator';
import { Route } from './route.decorator';
import { Model } from '../../common/models/model';
import { Response } from './response';
import { Request } from './request';
Expand All @@ -25,7 +25,7 @@ export abstract class ResourceController<M extends Model> extends AbstractContro
* @param response
* @returns {any}
*/
@Action('GET', '/:id')
@Route('GET', '/:id')
public getOne(request: Request, response: Response): Promise<Response> {

this.logger.debug('reading params', request);
Expand All @@ -41,7 +41,7 @@ export abstract class ResourceController<M extends Model> extends AbstractContro
* @param response
* @returns {any}
*/
@Action('GET', '/')
@Route('GET', '/')
public getMany(request: Request, response: Response): Promise<Response> {

return this.modelStore
Expand Down
56 changes: 56 additions & 0 deletions src/server/controllers/route.decorator.spec.ts
@@ -0,0 +1,56 @@
import { it, inject, beforeEachProviders, expect, describe } from '@angular/core/testing';
import { Request } from '../controllers/request';
import { Response } from '../controllers/response';
import { AbstractController } from '../controllers/abstract.controller';
import { Injectable, Injector, provide } from '@angular/core';
import { Logger } from '../../common/services/logger.service';
import { Server, RouteConfig } from '../servers/abstract.server';
import { LoggerMock } from '../../common/services/logger.service.spec';
import { ServerMock } from '../servers/abstract.server.spec';
import { RemoteCli } from '../services/remoteCli.service';
import { RemoteCliMock } from '../services/remoteCli.service.spec';
import { Route } from './route.decorator';
import { RouteBase } from './routeBase.decorator';

@Injectable()
@RouteBase('base')
class TestController extends AbstractController {

constructor(server: Server, logger: Logger) {
super(server, logger);
}

@Route('PUT', '/test/:id')
public testMethod(request: Request, response: Response): Response {
return response;
}

}

const providers = [
TestController,
provide(Server, {useClass: ServerMock}),
provide(Logger, {useClass: LoggerMock}),
provide(RemoteCli, {useClass: RemoteCliMock}),
];

describe('@Route & @RouteBase decorators', () => {

beforeEachProviders(() => providers);

it('Registers a route definition with the server ',
inject([TestController, Injector, Server],
(c: TestController, i: Injector, s: Server) => {

let controller = c.registerInjector(i)
.registerRoutes();

const routeConfig:RouteConfig = s.getRoutes()
.find((route: RouteConfig) => route.methodName == 'testMethod');

expect(routeConfig.method).toEqual('PUT');
expect(routeConfig.path).toEqual(process.env.API_BASE + '/base/test/:id');

}));

});
@@ -1,15 +1,14 @@
import { ActionType } from './abstract.controller';

import { HttpMethod } from '../servers/abstract.server';
/**
* Decorator for registering a basic action method in a controller
* @param method
* @param route
* @returns {function(any, string, TypedPropertyDescriptor<T>): undefined}
* @returns {function(any, string, TypedPropertyDescriptor<T>): void}
* @constructor
*/
export function Action<T>(method: ActionType, route: string): MethodDecorator {
export function Route<T>(method: HttpMethod, route: string): MethodDecorator {

return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {
return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): void {

target.registerActionMethod(propertyKey, method, route);
};
Expand Down

0 comments on commit 8054c10

Please sign in to comment.