Presupuestador_web/server/src/contexts/common/infrastructure/express/ExpressController.ts

232 lines
5.4 KiB
TypeScript
Raw Normal View History

2024-04-23 15:29:38 +00:00
import * as express from "express";
import { URL } from "url";
import {
IErrorExtra_Response_DTO,
IError_Response_DTO,
} from "@shared/contexts";
import { UseCaseError } from "../../application";
import { IServerError } from "../../domain/errors";
2024-05-15 19:56:22 +00:00
import { IController } from "../Controller.interface";
2024-04-23 15:29:38 +00:00
import { InfrastructureError } from "../InfrastructureError";
import { ProblemDocument, ProblemDocumentExtension } from "./ProblemDocument";
export abstract class ExpressController implements IController {
protected req: express.Request;
protected res: express.Response;
protected next: express.NextFunction;
protected serverURL: string = "";
protected file: any;
protected abstract executeImpl(): Promise<void | any>;
public execute(
req: express.Request,
res: express.Response,
2024-05-15 19:56:22 +00:00
next: express.NextFunction,
2024-04-23 15:29:38 +00:00
): void {
this.req = req;
this.res = res;
this.next = next;
this.serverURL = `${
new URL(
2024-05-15 19:56:22 +00:00
`${this.req.protocol}://${this.req.get("host")}${this.req.originalUrl}`,
2024-04-23 15:29:38 +00:00
).origin
}/api/v1`;
this.file = this.req && this.req["file"]; // <-- ????
this.executeImpl();
}
public ok<T>(dto?: T) {
if (dto) {
return this._jsonResponse(200, dto);
}
return this.res.status(200).send();
}
public fail(error: IServerError) {
console.group("ExpressController FAIL RESPONSE ====================");
console.log(error);
console.trace("Show me");
console.groupEnd();
return this._errorResponse(500, error ? error.toString() : "Fail");
}
public created<T>(dto?: T) {
if (dto) {
return this.res.status(201).json(dto).send();
}
return this.res.status(201).send();
}
public noContent() {
return this.res.status(204).send();
}
public download(filepath: string, filename: string, done?: any) {
return this.res.download(filepath, filename, done);
}
public clientError(message?: string) {
return this._errorResponse(400, message);
}
public unauthorizedError(message?: string) {
return this._errorResponse(401, message);
}
public paymentRequiredError(message?: string) {
return this._errorResponse(402, message);
}
public forbiddenError(message?: string) {
return this._errorResponse(403, message);
}
public notFoundError(message: string, error?: IServerError) {
return this._errorResponse(404, message, error);
}
public conflictError(message: string, error?: IServerError) {
return this._errorResponse(409, message, error);
}
public invalidInputError(message?: string, error?: InfrastructureError) {
return this._errorResponse(422, message, error);
}
public tooManyError(message: string, error?: Error) {
return this._errorResponse(429, message, error);
}
public internalServerError(message?: string, error?: IServerError) {
return this._errorResponse(500, message, error);
}
public todoError(message?: string) {
return this._errorResponse(501, message);
}
public unavailableError(message?: string) {
return this._errorResponse(503, message);
}
private _jsonResponse(
statusCode: number,
2024-05-15 19:56:22 +00:00
jsonPayload: any,
2024-04-23 15:29:38 +00:00
): express.Response<any> {
return this.res.status(statusCode).json(jsonPayload).send();
}
private _errorResponse(
statusCode: number,
message?: string,
2024-05-15 19:56:22 +00:00
error?: Error | InfrastructureError,
2024-04-23 15:29:38 +00:00
): express.Response<IError_Response_DTO> {
const context = {};
if (Object.keys(this.res.locals).length) {
if ("user" in this.res.locals) {
context["user"] = this.res.locals.user;
}
}
if (Object.keys(this.req.params).length) {
context["params"] = this.req.params;
}
if (Object.keys(this.req.query).length) {
context["query"] = this.req.query;
}
if (Object.keys(this.req.body).length) {
context["body"] = this.req.body;
}
const extension = new ProblemDocumentExtension({
context,
extra: error ? { ...this._processError(error) } : {},
});
return this._jsonResponse(
statusCode,
new ProblemDocument(
{
status: statusCode,
detail: message,
instance: this.req.baseUrl,
},
2024-05-15 19:56:22 +00:00
extension,
),
2024-04-23 15:29:38 +00:00
);
}
private _processError(
2024-05-15 19:56:22 +00:00
error: Error | InfrastructureError,
2024-04-23 15:29:38 +00:00
): IErrorExtra_Response_DTO {
/**
*
*
*
{
code: "INVALID_INPUT_DATA",
payload: {
label: "tin",
path: "tin", // [{path: "first_name"}, {path: "last_name"}]
},
name: "UseCaseError",
}
{
code: "INVALID_INPUT_DATA",
payload: [
{
tin: "{tin} is not allowed to be empty",
},
{
first_name: "{first_name} is not allowed to be empty",
},
{
last_name: "{last_name} is not allowed to be empty",
},
{
company_name: "{company_name} is not allowed to be empty",
},
],
name: "InfrastructureError",
}
*/
const useCaseError = <UseCaseError>error;
const payload = !Array.isArray(useCaseError.payload)
? Array(useCaseError.payload)
: useCaseError.payload;
const errors = payload.map((item) => {
if (item.path) {
return item.path
? {
[String(item.path)]: useCaseError.message,
}
: {};
} else {
return item;
}
});
return {
errors,
};
}
}