refactor: optimize framework

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2019-06-21 12:30:30 +08:00
parent b6443f805d
commit dc46ab904a
7 changed files with 57 additions and 55 deletions

View File

@ -1,7 +1,7 @@
import { Container, interfaces as inversify_interfaces } from 'inversify' import { Container, interfaces as inversify_interfaces } from 'inversify'
import { TYPE, interfaces as express_interfaces } from 'inversify-express-utils' import { TYPE, interfaces as express_interfaces } from 'inversify-express-utils'
import { METADATA_KEY, VAILD_TYPE } from './constants' import { METADATA_KEY } from './constants'
import { interfaces } from './interfaces' import { VaildError } from './interfaces'
import { getVaildMethodMetadata, getVaildControllerMetadata, getVaildModelMetadata } from './utils' import { getVaildMethodMetadata, getVaildControllerMetadata, getVaildModelMetadata } from './utils'
let handler = { let handler = {
@ -12,32 +12,24 @@ let handler = {
// loop @Valid params // loop @Valid params
for (const param of methodParams) { for (const param of methodParams) {
// get function argument value // get function argument value
let origin = argumentsList[param.index] let origin = argumentsList[param.index];
let props = getVaildModelMetadata(param.type); let props = getVaildModelMetadata(param.type);
for (const prop of props) { for (const prop of props) {
let propValue = origin[prop.name]; if (!prop.handle(origin[prop.name])) {
switch (prop.type) { throw new VaildError(prop.message);
case VAILD_TYPE.NOT_BLANK:
if (!propValue) {
throw new Error(prop.message);
}
break;
case VAILD_TYPE.NOT_NULL:
if (propValue == undefined) {
throw new Error(prop.message);
}
break;
default:
throw new Error('Unkonw Vaild Type!')
} }
} }
} }
return target.apply(thisArgument, argumentsList); return target.apply(thisArgument, argumentsList);
} catch (ex) { } catch (ex) {
res.status(400).json({ if (ex instanceof VaildError) {
status: 400, res.status(400).json({
message: ex.message status: 400,
}) message: ex.message
})
return;
}
throw ex;
} }
} }
} }

View File

@ -1,7 +1,7 @@
import 'reflect-metadata' import 'reflect-metadata'
import { METADATA_KEY, VAILD_TYPE } from './constants'; import { METADATA_KEY, VAILD_TYPE } from './constants';
import { getVaildControllerMetadata, getVaildModelMetadata } from './utils' import { getVaildControllerMetadata, getVaildModelMetadata } from './utils'
import { interfaces } from './interfaces' import { VaildFunction, interfaces } from './interfaces'
/** /**
* ParameterVaild * ParameterVaild
*/ */
@ -20,18 +20,26 @@ export function Vaild(): ParameterDecorator {
} }
} }
let vaildFunctions: {
[methodName: string]: VaildFunction;
} = {};
/** /**
* Vaild Blank String * Vaild Blank String
* @param message Error Message * @param message Error Message
*/ */
export const NotBlank: (message?: string) => PropertyDecorator = vaildDecoratorFactory(VAILD_TYPE.NOT_BLANK); export const NotBlank: (message?: string) => PropertyDecorator = vaildDecoratorFactory(
VAILD_TYPE.NOT_BLANK, (param) => !!param);
/** /**
* Vaild Null Param * Vaild Null Param
* @param message Error Message * @param message Error Message
*/ */
export const NotNull: (message?: string) => PropertyDecorator = vaildDecoratorFactory(VAILD_TYPE.NOT_NULL); export const NotNull: (message?: string) => PropertyDecorator = vaildDecoratorFactory(
VAILD_TYPE.NOT_NULL, (param) => param !== undefined
);
function vaildDecoratorFactory(type: VAILD_TYPE): () => PropertyDecorator { function vaildDecoratorFactory(type: VAILD_TYPE, handle: VaildFunction): () => PropertyDecorator {
vaildFunctions[type] = handle;
return function(message?: string): PropertyDecorator { return function(message?: string): PropertyDecorator {
return vaildProperty(type, message); return vaildProperty(type, message);
}; };
@ -41,9 +49,10 @@ function vaildProperty(type: VAILD_TYPE, message?: string): PropertyDecorator {
return (model: Object, propertyKey: string) => { return (model: Object, propertyKey: string) => {
let metadataList: interfaces.PropertyMetadata[] = getVaildModelMetadata(model.constructor); let metadataList: interfaces.PropertyMetadata[] = getVaildModelMetadata(model.constructor);
metadataList.push({ metadataList.push({
type: type,
name: propertyKey, name: propertyKey,
message: message || `model ${model.constructor.name} property ${propertyKey} vaild failed => ${VAILD_TYPE[type]}`, message: message || `model ${model.constructor.name} property ${propertyKey} vaild failed => ${VAILD_TYPE[type]}`,
type: type handle: vaildFunctions[type]
}) })
Reflect.defineMetadata(METADATA_KEY.vaildModel, metadataList, model.constructor); Reflect.defineMetadata(METADATA_KEY.vaildModel, metadataList, model.constructor);
} }

View File

@ -1,6 +1,10 @@
import { VAILD_TYPE } from './constants' import { VAILD_TYPE } from './constants'
namespace interfaces { export class VaildError extends Error { }
export declare type VaildFunction = (param: object) => boolean;
export namespace interfaces {
export interface MethodMetadata { export interface MethodMetadata {
[methodName: string]: ParameterMetadata[]; [methodName: string]: ParameterMetadata[];
} }
@ -11,10 +15,9 @@ namespace interfaces {
} }
export interface PropertyMetadata { export interface PropertyMetadata {
type: VAILD_TYPE;
name: string; name: string;
message: string; message: string;
type: VAILD_TYPE; handle: VaildFunction;
} }
} }
export { interfaces };

View File

@ -13,7 +13,7 @@ const TABLE = 'users'
class ExampleModel { class ExampleModel {
_id: string; _id: string;
@NotBlank("用户名不得为空!") @NotBlank("username must not be blank!")
username: string; username: string;
password: string; password: string;
@NotNull() @NotNull()
@ -49,8 +49,8 @@ export class Controller {
public async create( public async create(
@Vaild() @requestBody() model: ExampleModel @Vaild() @requestBody() model: ExampleModel
): Promise<ExampleModel> { ): Promise<ExampleModel> {
return model;
//return this.client.insertOne(model); //return this.client.insertOne(model);
return this.client.findOneById('5d0af7c039179a28de618cb8');
} }
@httpPost('/:id') @httpPost('/:id')

View File

@ -2,18 +2,21 @@ import 'reflect-metadata';
import * as express from "express"; import * as express from "express";
import { InversifyExpressServer, interfaces, getRouteInfo } from 'inversify-express-utils'; import { InversifyExpressServer, interfaces, getRouteInfo } from 'inversify-express-utils';
import * as bodyParser from 'body-parser'; import * as bodyParser from 'body-parser';
import { buildProviderModule } from 'cc-server-ioc';
import { rebuildServer } from 'cc-server-binding' import { rebuildServer } from 'cc-server-binding'
import { container, buildProviderModule } from 'cc-server-ioc';
import * as prettyjson from "prettyjson"; import * as prettyjson from "prettyjson";
import { Container } from 'inversify';
export class CcServerBoot { export class CcServerBoot {
private server: InversifyExpressServer; private _container: Container;
private serverInstance: express.Application; private _server: InversifyExpressServer;
constructor() { private _serverInstance: express.Application;
container.load(buildProviderModule()); constructor(container?: Container) {
this._container = container || new Container();
this._container.load(buildProviderModule());
// start the server // start the server
this.server = new InversifyExpressServer(container); this._server = new InversifyExpressServer(this._container);
this.server.setConfig((app) => { this._server.setConfig((app) => {
app.use(bodyParser.urlencoded({ app.use(bodyParser.urlencoded({
extended: true extended: true
})); }));
@ -23,23 +26,23 @@ export class CcServerBoot {
} }
public setConfig(fn: interfaces.ConfigFunction) { public setConfig(fn: interfaces.ConfigFunction) {
this.server.setConfig(fn) this._server.setConfig(fn)
} }
public setErrorConfig(fn: interfaces.ConfigFunction) { public setErrorConfig(fn: interfaces.ConfigFunction) {
this.server.setErrorConfig(fn) this._server.setErrorConfig(fn)
} }
public build() { public build() {
this.serverInstance = this.server.build(); this._serverInstance = this._server.build();
rebuildServer(container); rebuildServer(this._container);
return this.serverInstance; return this._serverInstance;
} }
public start() { public start(port: number = 80) {
const routeInfo = getRouteInfo(container); const routeInfo = getRouteInfo(this._container);
console.log(prettyjson.render({ routes: routeInfo })); console.log(prettyjson.render({ routes: routeInfo }));
this.serverInstance.listen(80); this._serverInstance.listen(port);
console.log('Server started on port 80 :)'); console.log(`Server started on port ${port} :)`);
} }
} }

View File

@ -2,11 +2,6 @@ import "reflect-metadata";
import { Container, inject, interfaces } from 'inversify'; import { Container, inject, interfaces } from 'inversify';
import { autoProvide, provide, fluentProvide, buildProviderModule } from 'inversify-binding-decorators'; import { autoProvide, provide, fluentProvide, buildProviderModule } from 'inversify-binding-decorators';
let container = new Container();
// Reflects all decorators provided by this package and packages them into
// a module to be loaded by the container
// container.load(buildProviderModule());
const provideNamed = (identifier: interfaces.ServiceIdentifier<any>, name: string) => { const provideNamed = (identifier: interfaces.ServiceIdentifier<any>, name: string) => {
return fluentProvide(identifier) return fluentProvide(identifier)
.whenTargetNamed(name) .whenTargetNamed(name)
@ -19,4 +14,4 @@ const provideSingleton = (identifier: interfaces.ServiceIdentifier<any>) => {
.done(); .done();
}; };
export { container, autoProvide, provide, provideNamed, provideSingleton, inject, buildProviderModule }; export { autoProvide, provide, provideNamed, provideSingleton, inject, buildProviderModule };