import { APIGatewayEvent, Callback, Context, Handler } from 'aws-lambda'; import { log } from '../system'; import { Request } from './request'; import { Response } from './response'; import { Middleware } from '../middleware/middleware'; import { HTTPError, InternalError, MethodNotAllowed } from './errors'; /** * The base endpoint class implemented by all endpoints. * * @export * @class Endpoint */ export class Endpoint { /** * An array of middleware objects. * * @type {Middleware[]} * @memberof Endpoint */ middleware: Middleware[] = []; /** * An array of references to processRequest handlers. * * @type {any[]} * @memberof Endpoint */ before: any[] = []; /** * An array of references to processResponse handlers. * * @type {any[]} * @memberof Endpoint */ after: any[] = []; /** * The base handler registered with serverless. Returns an async function * that handles standard serverless handler arguments. The returned * function mounts all middleware and a verb-based handler function based * on the request method. Middleware request processors are called first, * then the verb-based handler, then middleware response processors. If an * error is thrown, it is converted to a response object and sent. * * @throws {HTTPError} * @returns async (evt: APIGatewayEvent, ctx: Context) * @memberof Endpoint */ handler() { return async (evt: APIGatewayEvent, ctx: Context | any) => { let res = new Response(); let req = new Request(evt); let verb = evt.httpMethod.toLowerCase(); let callstack = [ ...this.before, this[verb], ...this.after.reverse() ]; try { for (let call of callstack) { await call(req, res); } } catch (exc) { log.error(exc); if (exc instanceof HTTPError) { res = exc.toResponse(res); } else { let err = new InternalError(exc.message); res = err.toResponse(res); } } return res.toLambdaResponse(); } } /** * Adds a middleware object to the stack. * * @param {Middleware} middleware * @memberof Endpoint */ register(middleware: Middleware) { this.middleware.push(middleware); this.before.push(middleware.processRequest); this.after.push(middleware.processResponse); } /** * Base implementation of GET. * * @param {Request} req * @param {Response} res * @throws {MethodNotAllowed} * @returns {Promise} * @memberof Endpoint */ async get(req: Request, res: Response): Promise { throw new MethodNotAllowed(); } /** * Base implementation of PUT. * * @param {Request} req * @param {Response} res * @throws {MethodNotAllowed} * @returns {Promise} * @memberof Endpoint */ async put(req: Request, res: Response): Promise { throw new MethodNotAllowed(); } /** * Base implementation of POST. * * @param {Request} req * @param {Response} res * @throws {MethodNotAllowed} * @returns {Promise} * @memberof Endpoint */ async post(req: Request, res: Response): Promise { throw new MethodNotAllowed(); } /** * Base implementation of DELETE. * * @param {Request} req * @param {Response} res * @throws {MethodNotAllowed} * @returns {Promise} * @memberof Endpoint */ async delete(req: Request, res: Response): Promise { throw new MethodNotAllowed(); } }