import * as express from 'express' ; import Joi from 'joi' ; import { Account } from '../../../../modules/account/domain/account' ; import { DecodedExpressRequest } from './decodedRequest' ; import { logger } from "../../../../logger" ; export interface NettuAppRequest < B = { } , P = { } > { body : B ; pathParams : P ; account ? : Account ; } export abstract class BaseController < B = { } , P = { } > { private bodySchema : Joi . ObjectSchema < B > ; private pathParamsSchema : Joi . ObjectSchema < P > ; constructor ( body , pathParams ) { this . bodySchema = body ? body : Joi . object ( { } ) ; this . pathParamsSchema = pathParams ? pathParams : Joi . object ( { } ) ; } protected abstract executeImpl ( req , res ) ; public async execute ( req , _res ) { const res = new NettuAppResponse ( _res ) ; const reqBody = req . body != null ? req . body : { } ; const reqPathParams = req . params != null ? req . params : { } ; const bodySchemaValidationRes = this . bodySchema . validate ( reqBody ) ; if ( bodySchemaValidationRes . error ) { return res . badClientData ( bodySchemaValidationRes . error . message ) ; } const pathParamsSchemaValidationRes = this . pathParamsSchema . validate ( reqPathParams ) ; if ( pathParamsSchemaValidationRes . error ) { return res . badClientData ( pathParamsSchemaValidationRes . error . message ) ; } let account ; const maybeDecodedReq = req as DecodedExpressRequest ; if ( maybeDecodedReq . decoded && maybeDecodedReq . decoded . account ) { account = maybeDecodedReq . decoded . account ; } const nettuReq = { body : bodySchemaValidationRes . value , pathParams : pathParamsSchemaValidationRes . value , account , } ; try { this . executeImpl ( nettuReq , res ) ; } catch ( error ) { logger . error ( { error : error } , `[BaseController]: Uncaught controller error` ) ; res . fail ( ) ; } } } export class NettuAppResponse { private res : express . Response ; private sent : boolean ; constructor ( res ) { this . sent = false ; this . res = res ; } private jsonResponse ( code , dto ) { if ( this . sent ) { throw new Error ( 'Cannot send response twice' ) ; } this . sent = true ; this . res . status ( code ) . json ( dto ) ; } public ok < T > ( dto ? ) { return this . jsonResponse ( 200 , dto ) ; } public created < T > ( dto ? ) { return this . jsonResponse ( 201 , dto ) ; } public badClientData ( message ? ) { return this . jsonResponse ( 400 , { message : message ? message : 'Bad client request' , } ) ; } public unauthorized ( message ? ) { return this . jsonResponse ( 401 , { message : message ? message : 'Unauthorized' , } ) ; } public forbidden ( message ? ) { return this . jsonResponse ( 403 , { message : message ? message : 'Forbidden' , } ) ; } public notFound ( message ? ) { return this . jsonResponse ( 404 , { message : message ? message : 'Not found' , } ) ; } public conflict ( message ? ) { return this . jsonResponse ( 409 , { message : message ? message : 'Conflict' , } ) ; } public fail ( ) { return this . jsonResponse ( 500 , { message : 'An unexpected error occurred' , } ) ; } }