I am developing logging middleware, and want to log response body in 500 responses. In middleware im setting a callback for "finish" event on request, that emits after the response was sent, but no response body in Response
object is present.
I assume there is no body because nest js with express under the hood sends response by chanks, and does not saves it in Request
or Response
objects.
But I hope there is a workaround to get response body from Response
object in middleware that someone found. The example of middleware class im working on:
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(request: Request, response: Response, next: NextFunction): void {
const { ip, method, originalUrl } = request;
const userAgent = request.get("user-agent") || "";
response.on("finish", () => {
const { statusCode } = response;
const contentLength = response.get("content-length");
const basicRequestMetaInfo = {
method,
originalUrl,
statusCode,
... // other data
};
if (this.isErroneousStatusCode(statusCode)) {
const additionalRequestMetaInfo = {
body: response.body, // The place i want to reach Response body
};
this.winstonLoggerErrorLevel.error({
...basicRequestMetaInfo,
...additionalRequestMetaInfo,
});
return;
}
this.winstonLoggerInfoLevel.info(basicRequestMetaInfo);
});
next();
}
}
This article explains how to transform the buffer chunks in a readable response.
This is the code from the article that you would need, with some typescript typing you can change as needed:
const getResponseLog = (res: Response) => {
const rawResponse = res.write;
const rawResponseEnd = res.end;
const chunkBuffers = [];
res.write = (...chunks) => {
const resArgs = [];
for (let i = 0; i < chunks.length; i++) {
resArgs[i] = chunks[i];
if (!resArgs[i]) {
res.once('drain', res.write);
i--;
}
}
if (resArgs[0]) {
chunkBuffers.push(Buffer.from(resArgs[0]));
}
return rawResponse.apply(res, resArgs);
};
console.log(`Done writing, beginning res.end`);
res.end = (...chunk) => {
const resArgs = [];
for (let i = 0; i < chunk.length; i++) {
resArgs[i] = chunk[i];
}
if (resArgs[0]) {
chunkBuffers.push(Buffer.from(resArgs[0]));
}
const body = Buffer.concat(chunkBuffers).toString('utf8');
res.setHeader('origin', 'restjs-req-res-logging-repo');
const responseLog = {
response: {
statusCode: res.statusCode,
body: JSON.parse(body) || body || {},
// Returns a shallow copy of the current outgoing headers
headers: res.getHeaders(),
},
};
console.log('res: ', responseLog);
rawResponseEnd.apply(res, resArgs);
return responseLog as unknown as Response;
};
};