typenexus
Version:
TypeNexus is a good tool for API encapsulation and management. It provides a clean and lightweight way to package TypeORM functionality, helping you build applications faster while reducing template code redundancy and type conversion work.
87 lines (83 loc) • 3.28 kB
text/typescript
import { MetadataBuilder } from './builder/MetadataBuilder.js';
import { Driver } from './Driver.js';
import { TypeNexusOptions } from './DriverOptions.js';
import { ActionMetadata } from './metadata/ActionMetadata.js';
import { Action } from './Action.js';
import { isPromiseLike } from './utils/isPromiseLike.js';
import { ActionParameterHandler } from './ActionParameterHandler.js';
export class Controllers<T extends Driver> {
/**
* Used to build metadata objects for controllers and middlewares.
*/
private metadataBuilder: MetadataBuilder;
/**
* Used to check and handle controller action parameters.
*/
private parameterHandler: ActionParameterHandler<T>;
constructor(private driver: T, private options: TypeNexusOptions) {
this.parameterHandler = new ActionParameterHandler<T>(driver);
this.metadataBuilder = new MetadataBuilder(this.options);
}
registerControllers(classes?: Function[]): this {
const controllers = this.metadataBuilder.buildControllerMetadata(classes);
controllers.map((controller) => {
controller.actions.forEach((actionMetadata) => {
this.driver.registerAction(actionMetadata, (action) => {
this.executeAction(actionMetadata, action);
});
});
});
return this;
}
/**
* Registers middleware that run before controller actions.
*/
registerMiddlewares(type: 'before' | 'after', classes: Function[], option: TypeNexusOptions): this {
this.metadataBuilder
.buildMiddlewareMetadata(classes)
.filter((middleware) => middleware.global && middleware.type === type)
.sort((middleware1, middleware2) => middleware2.priority - middleware1.priority)
.forEach((middleware) => this.driver.registerMiddleware(middleware, option));
return this;
}
/**
* Executes given controller action.
*/
protected executeAction(actionMetadata: ActionMetadata, action: Action) {
// compute all parameters
const paramsPromises = actionMetadata.params
.sort((param1, param2) => param1.index - param2.index)
.map((param) => {
return this.parameterHandler.handle(action, param);
});
// compute all constructor parameters
const paramsConstructor = actionMetadata.paramsConstructor
.sort((param1, param2) => param1.index - param2.index)
.map((param) => this.parameterHandler.handleConstructor(action, param))
.filter(Boolean);
return Promise.all(paramsPromises)
.then((params) => {
const result = actionMetadata.callMethod(params, paramsConstructor, action);
return this.handleCallMethodResult(result, actionMetadata, action);
})
.catch((error) => {
return this.driver.handleError(error, actionMetadata, action);
});
}
/**
* Handles result of the action method execution.
*/
protected handleCallMethodResult(result: any, action: ActionMetadata, options: Action): any {
if (isPromiseLike(result)) {
return result
.then((data) => {
return this.handleCallMethodResult(data, action, options);
})
.catch((error) => {
return this.driver.handleError(error, action, options);
});
} else {
return this.driver.handleSuccess(result, action, options);
}
}
}