Last active
May 21, 2024 16:52
-
-
Save PatrickJS/c5b62665f76018b6b8d42505a9dabfde to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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