@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
JavaScript
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