Skip to content

Instantly share code, notes, and snippets.

@PatrickJS
Last active May 21, 2024 16:52
Show Gist options
  • Save PatrickJS/c5b62665f76018b6b8d42505a9dabfde to your computer and use it in GitHub Desktop.
Save PatrickJS/c5b62665f76018b6b8d42505a9dabfde to your computer and use it in GitHub Desktop.
/* Features */
// - remove cache headers for /q-data.json
export const handler = async (event, context) => {
try {
const [req, res, ctx, target] = eventNormalize(event, context); // 'ctx' is the context object
// Your business logic here
// Example of modifying the response based on URI
if (req.uri.endsWith('/q-data.json')) {
res.headers['cache-control'] = 'no-cache';
}
// Log some context information if needed
console.log(`Remaining time: ${ctx.getRemainingTimeInMillis()} ms`);
// Return the normalized response
return eventResponseNormalize(event, res, target);
} catch (error) {
console.error(error);
const errorResponse = {
statusCode: 500,
headers: { 'content-type': 'text/plain' },
body: 'Internal Server Error'
};
return eventResponseNormalize(event, errorResponse, 'Unknown');
}
};
// eventHelpers.js
// Standardize headers to key-value pairs
function normalizeHeaders(headers) {
if (!headers) return {};
const normalized = {};
for (const key in headers) {
normalized[key.toLowerCase()] = headers[key];
}
return normalized;
}
// Format headers correctly for each deployment target
function formatHeadersForResponse(headers, target) {
if (target === 'Lambda@Edge') {
const formattedHeaders = {};
for (const [key, value] of Object.entries(headers)) {
formattedHeaders[key.toLowerCase()] = [{ key, value }];
}
return formattedHeaders;
}
return headers; // API Gateway and ALB can use normalized simple key-value pairs
}
// Normalize event to extract request, initial response objects, and context
function eventNormalize(event, context) {
let req, res, target;
if (event?.Records?.[0]?.cf) {
// Lambda@Edge event normalization
const request = event.Records[0].cf.request;
res = event.Records[0].cf.response;
target = 'Lambda@Edge';
req = {
uri: request.uri,
method: request.method,
headers: normalizeHeaders(request.headers),
body: request.body
};
} else if (event.httpMethod) {
// API Gateway event normalization
req = {
uri: event.path,
method: event.httpMethod,
headers: normalizeHeaders(event.headers),
body: event.body
};
res = {
statusCode: 200,
headers: {},
body: ''
};
target = 'APIGateway';
} else if (event?.requestContext?.elb) {
// ALB event normalization
req = {
uri: event.path,
method: event.httpMethod,
headers: normalizeHeaders(event.headers),
body: event.body
};
res = {
statusCode: 200,
headers: {},
body: ''
};
target = 'ALB';
} else if (event.__type && event.__type === 'AWSGlobalAcceleratorEvent') {
// Placeholder for AWS Global Accelerator custom events
req = {
// Customize this part based on your AWS Global Accelerator input
uri: event.path,
method: event.method,
headers: normalizeHeaders(event.headers),
body: event.body
};
res = {
statusCode: 200,
headers: {},
body: ''
};
target = 'AWSGlobalAccelerator';
} else {
// Handle other event types if applicable
throw new Error('Unsupported event type');
}
return [req, res, context, target];
}
// Normalize custom responses back to the appropriate format
function eventResponseNormalize(event, response, target) {
const formattedHeaders = formatHeadersForResponse(response.headers, target);
if (target === 'Lambda@Edge') {
// Lambda@Edge response normalization
return {
status: response.statusCode.toString(),
statusDescription: response.statusDescription || 'OK',
headers: formattedHeaders,
body: response.body
};
} else if (target === 'APIGateway' || target === 'ALB') {
// API Gateway and ALB response normalization
return {
statusCode: response.statusCode || 200,
headers: formattedHeaders,
body: response.body || ''
};
} else if (target === 'AWSGlobalAccelerator') {
// AWS Global Accelerator response normalization
return {
statusCode: response.statusCode || 200,
headers: formattedHeaders,
body: response.body || ''
};
} else {
// Handle other event types if applicable
throw new Error('Unsupported event type');
}
}
/* Features */
// - remove cache headers for /q-data.json
// Define your business logic in a separate function
export const handler = createLambdaHandler(main)
async function main(req, res, ctx) {
// Your business logic here
// Example of modifying the response based on URI
if (req.uri.endsWith('/qdata.json')) {
res.headers['cache-control'] = 'no-cache';
}
// Log some context information if needed
// console.log(`Remaining time: ${ctx.getRemainingTimeInMillis()} ms`);
// Return the custom response
return res;
}
//
//
//
// Helpers-----------------------
//
//
//
/**
* Wrapper to create a Lambda handler with normalized request and response objects.
* @param {Function} businessLogic - The function containing your business logic.
* @returns {Function} - The Lambda handler function.
*/
function createLambdaHandler(businessLogic) {
return async (event, context) => {
try {
const [req, res, ctx, target] = eventNormalize(event, context);
// Run the business logic
const customResponse = await businessLogic(req, res, ctx);
// Return the normalized response
return eventResponseNormalize(event, customResponse, target);
} catch (error) {
console.error(error);
const errorResponse = {
statusCode: 500,
headers: { 'content-type': 'text/plain' },
body: 'Internal Server Error'
};
// Return the error response
return eventResponseNormalize(event, errorResponse, 'Unknown');
}
};
}
// eventHelpers.js
// Standardize headers to key-value pairs
function normalizeHeaders(headers) {
if (!headers) return {};
const normalized = {};
for (const key in headers) {
normalized[key.toLowerCase()] = headers[key];
}
return normalized;
}
// Format headers correctly for each deployment target
function formatHeadersForResponse(headers, target) {
if (target === 'Lambda@Edge') {
const formattedHeaders = {};
for (const [key, value] of Object.entries(headers)) {
formattedHeaders[key.toLowerCase()] = [{ key, value }];
}
return formattedHeaders;
}
return headers; // API Gateway and ALB can use normalized simple key-value pairs
}
// Normalize event to extract request, initial response objects, and context
function eventNormalize(event, context) {
let req, res, target;
if (event?.Records?.[0]?.cf) {
// Lambda@Edge event normalization
const request = event.Records[0].cf.request;
res = event.Records[0].cf.response;
target = 'Lambda@Edge';
req = {
uri: request.uri,
method: request.method,
headers: normalizeHeaders(request.headers),
body: request.body
};
} else if (event.httpMethod) {
// API Gateway event normalization
req = {
uri: event.path,
method: event.httpMethod,
headers: normalizeHeaders(event.headers),
body: event.body
};
res = {
statusCode: 200,
headers: {},
body: ''
};
target = 'APIGateway';
} else if (event?.requestContext?.elb) {
// ALB event normalization
req = {
uri: event.path,
method: event.httpMethod,
headers: normalizeHeaders(event.headers),
body: event.body
};
res = {
statusCode: 200,
headers: {},
body: ''
};
target = 'ALB';
} else if (event.__type && event.__type === 'AWSGlobalAcceleratorEvent') {
// Placeholder for AWS Global Accelerator custom events
req = {
// Customize this part based on your AWS Global Accelerator input
uri: event.path,
method: event.method,
headers: normalizeHeaders(event.headers),
body: event.body
};
res = {
statusCode: 200,
headers: {},
body: ''
};
target = 'AWSGlobalAccelerator';
} else {
// Handle other event types if applicable
throw new Error('Unsupported event type');
}
return [req, res, context, target];
}
// Normalize custom responses back to the appropriate format
function eventResponseNormalize(event, response, target) {
const formattedHeaders = formatHeadersForResponse(response.headers, target);
if (target === 'Lambda@Edge') {
// Lambda@Edge response normalization
return {
status: response.statusCode.toString(),
statusDescription: response.statusDescription || 'OK',
headers: formattedHeaders,
body: response.body
};
} else if (target === 'APIGateway' || target === 'ALB') {
// API Gateway and ALB response normalization
return {
statusCode: response.statusCode || 200,
headers: formattedHeaders,
body: response.body || ''
};
} else if (target === 'AWSGlobalAccelerator') {
// AWS Global Accelerator response normalization
return {
statusCode: response.statusCode || 200,
headers: formattedHeaders,
body: response.body || ''
};
} else {
// Handle other event types if applicable
throw new Error('Unsupported event type');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment