post-request-handler/handler.js

134 lines
4.0 KiB
JavaScript

// === Handler ===
export const postHandler = async (req, res) => {
try {
const modified = processPostRequest(req.body?.response);
return res.status(200).json(modified);
} catch (err) {
return handleError(err, res);
}
};
// === Core Processing ===
function processPostRequest(response) {
if (!response || typeof response !== 'object') {
throw new InvalidJsonContentTypeError('Missing or invalid response body', 400);
}
const modified = postRequestHandlerWrapper(response);
return modified;
}
// === Unified Error Handler ===
function handleError(err, res) {
const isJsonTypeError = err instanceof InvalidJsonContentTypeError ||
err?.message?.includes('Body content-type is not valid JSON');
const status = isJsonTypeError ? err.statusCode || 415 : 500;
return res.status(status).json({
error: err.name || 'InternalServerError',
message: err.message || 'Unexpected error occurred',
...(err.details && { details: err.details }),
});
}
let currentResponse = null;
let postContext = null;
function createPostContext() {
return {
addedHeaders: {},
removedHeaders: [],
modifiedBody: null,
modifiedStatus: null,
};
}
export function postRequestHandlerWrapper(response) {
postContext = createPostContext();
currentResponse = response;
postRequestHandler();
const ctx = postContext;
postContext = null;
currentResponse = null;
return ctx;
}
export function postRequestHandler() {
setHeader('x-post-transform', 'applied');
removeHeader('x-unwanted-header');
const body = getJsonBody();
if (body) {
body.modifiedAt = new Date().toISOString();
body.transformed = "transformed***********";
setJsonBody(body);
}
setStatus(202);
}
export function setHeader(key, value) {
if (!currentResponse?.headers) currentResponse.headers = {};
currentResponse.headers[key.toLowerCase()] = value;
postContext?.addedHeaders && (postContext.addedHeaders[key.toLowerCase()] = value);
}
export function removeHeader(key) {
if (currentResponse?.headers?.[key.toLowerCase()] !== undefined) {
delete currentResponse.headers[key.toLowerCase()];
postContext?.removedHeaders?.push(key.toLowerCase());
}
}
export function getHeader(key) {
if (!currentResponse?.headers) return null;
return currentResponse.headers[key.toLowerCase()] || null;
}
export function getJsonBody() {
if (!currentResponse?.body) return null;
const contentType = currentResponse.contentType || currentResponse.headers?.['content-type'] || '';
if (!contentType.includes('application/json')) {
throw new InvalidJsonContentTypeError();
}
try {
return typeof currentResponse.body === 'string'
? JSON.parse(currentResponse.body)
: currentResponse.body;
} catch (err) {
throw new InvalidJsonContentTypeError('Failed to parse JSON body', 415, { originalError: err });
}
}
export function setJsonBody(json) {
const contentType = currentResponse.contentType || currentResponse.headers?.['content-type'] || '';
if (!contentType.includes('application/json')) {
throw new InvalidJsonContentTypeError();
}
try {
currentResponse.body = JSON.stringify(json);
postContext && (postContext.modifiedBody = json);
} catch (err) {
throw new InvalidJsonContentTypeError('Failed to stringify JSON body', 415, { originalError: err });
}
}
export function setStatus(statusCode) {
if (typeof statusCode === 'number') {
currentResponse.status = statusCode;
postContext && (postContext.modifiedStatus = statusCode);
}
}
export class InvalidJsonContentTypeError extends Error {
constructor(message = 'Body content-type is not valid JSON', statusCode = 415, details = {}) {
super(message);
this.name = 'InvalidJsonContentTypeError';
this.statusCode = statusCode;
this.details = details;
}
}