UNPKG

@mikeycoxon/aws-lambda-event-http-router

Version:

AWS Lambda handler utility for HTTP REST request routing based on details in the APIGatewayProxyEvent

191 lines 5.91 kB
import { StatusCodes } from 'http-status-codes'; // the /i ignores case in regex evaluation const U_RE = new RegExp(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i); const F_RE = new RegExp(/\/[0-9a-zA-Z_\-]{3,255}\.[a-z0-9]{2,5}$/i); const GET_RE = new RegExp(/^GET/); const POST_RE = new RegExp(/^POST/); const PUT_RE = new RegExp(/^PUT/); const PATCH_RE = new RegExp(/^PATCH/); const DELETE_RE = new RegExp(/^DELETE/); export const GET = 'isGet'; export const POST = 'isPost'; export const PUT = 'isPut'; export const PATCH = 'isPatch'; export const DELETE = 'isDelete'; export const UUID = 'isPathUuid'; export const FILE = 'isPathFile'; export const ROUTE_KEY = 'eventRouteKey'; export class EventMap extends Map { constructor() { super(); } andResource(event, res) { super.set(res, resource(event, res)); return this; } andCustomIdFormat(event, format, name) { const matches = `${event.pathParameters?.proxy}`.match(format); console.debug(matches); let m = undefined; if (matches && matches?.length > 0) { m = matches.at(0); console.debug(`found match: ${m}`); } super.set(name, m); return this; } } export const withEvent = (event) => { const requestMap = new EventMap(); requestMap.set(UUID, isPathUuid(event)); requestMap.set(FILE, isPathFile(event)); requestMap.set(GET, isGet(event)); requestMap.set(POST, isPost(event)); requestMap.set(PUT, isPut(event)); requestMap.set(PATCH, isPatch(event)); requestMap.set(DELETE, isDelete(event)); requestMap.set(ROUTE_KEY, `${event.httpMethod} ${event.pathParameters?.proxy}`); return requestMap; }; export const isPathUuid = (event) => { const matches = `${event.pathParameters?.proxy}`.match(U_RE); console.debug(matches); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const isPathFile = (event) => { const matches = `${event.pathParameters?.proxy}`.match(F_RE); console.debug(matches); if (matches && matches?.length > 0) { const fm = matches.at(0); console.debug(`found match: ${fm}`); return fm; } }; export const resource = (event, resource) => { const r = new RegExp(`${resource}`, `i`); const matches = `${event.pathParameters?.proxy}`.match(r); console.debug(matches); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const isGet = (event) => { const matches = `${event.httpMethod}`.match(GET_RE); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const isPost = (event) => { const matches = `${event.httpMethod}`.match(POST_RE); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const isPut = (event) => { const matches = `${event.httpMethod}`.match(PUT_RE); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const isPatch = (event) => { const matches = `${event.httpMethod}`.match(PATCH_RE); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const isDelete = (event) => { const matches = `${event.httpMethod}`.match(DELETE_RE); if (matches && matches?.length > 0) { const m = matches.at(0); console.debug(`found match: ${m}`); return m; } }; export const stripLeadingSlash = (resourceString) => { if (!resourceString) { throw new NotFoundError('no resource at the end of event.pathParameters.proxy'); } return resourceString.replace('/', ''); }; export class Success { message; statusCode; constructor(message, statusCode) { this.message = message; this.statusCode = statusCode; } format() { return { statusCode: this.statusCode, headers: { 'content-type': 'text/plain' }, body: this.message || Object.keys(StatusCodes)[Object.values(StatusCodes).indexOf(this.statusCode)], }; } } export class ApiError extends Error { statusCode; constructor(message, statusCode) { super(message); Object.setPrototypeOf(this, ApiError.prototype); this.statusCode = statusCode; } format() { return { statusCode: this.statusCode, headers: { 'content-type': 'text/plain' }, body: this.message || Object.keys(StatusCodes)[Object.values(StatusCodes).indexOf(this.statusCode)], }; } } export class NotFoundError extends ApiError { constructor(message) { super(message, StatusCodes.NOT_FOUND); } } export class ForbiddenError extends ApiError { constructor(message) { super(message, StatusCodes.FORBIDDEN); } } export class UnauthorizedError extends ApiError { constructor(message) { super(message, StatusCodes.UNAUTHORIZED); } } export class BadRequestError extends ApiError { constructor(message) { super(message, StatusCodes.BAD_REQUEST); } } export class ServerError extends ApiError { constructor(message) { super(message, StatusCodes.INTERNAL_SERVER_ERROR); } } export class Created extends Success { constructor(message) { super(message, StatusCodes.CREATED); } } export class OK extends Success { constructor(message) { super(message, StatusCodes.OK); } } //# sourceMappingURL=index.js.map