Is there any way to get the response's HTTP status code in an interceptor, so that I could create prometheus metrics by HTTP status code?
@Injectable()
export class GlobalMetricsInterceptor implements NestInterceptor {
constructor(private metricsService: MetricsService) {}
public intercept(context: ExecutionContext, call: Observable<unknown>): Observable<unknown> {
const now: number = Date.now();
const requestedUrl: string = context.getArgByIndex<IncomingMessage>(0).url;
if (requestedUrl.startsWith('/v5/metrics')) {
return call.pipe();
}
this.metricsService.incrementHttpRequest();
return call.pipe(
finalize(() => {
console.log(`Done in ${Date.now() - now}ms`);
})
);
}
}
I believe this is a question better fitted for StackOverflow, but you should be able to do
context.switchToHttp().getResponse().statusCode
I've experienced statusCode
always being 200 in the interceptor. The following is not an elegant solution, but pushing the getResponse()
to the end of the call stack using setTimeout
has solved this issue for me:
return call.pipe(tap(() => {
setTimeout(() => {
console.log(context.switchToHttp().getResponse().statusCode)
}, 0);
}));
It seems like the interceptor is invoked before the final response code is set on the reponse object.
Actually, it's impossible for a few reasons:
What I would suggest instead:
@HttpCode()
metadata to ensure that nobody has overloaded a default status code.Hmm I think using the request and response objects from express or fastify and attach once listeners might be the more elegant solution then. I am worried it's not as generic and and elegant as hoped, but I hope you will ultimately come up with the best solution in the request prometheus metrics module.
Can you share how you currently enrich your services with prometheus metrics?
Dear all,
i recently stumbled upon the same problem, that i want to modify the HTTP Status Code in an interceptor. Consider the following example:
I created an ETagInterceptor
that calculates the Etag
of the response to be send back to my client. If the client makes another request to my API, he may send his etag via if-none-match
http header to the API. The API then processes the request and creates the response. If the new etag matches the if-none-match
header, the content shall be removed (i.e,. set to ''
) and the server must return with http code 304 (NOT MODIFIED)
.
I thought it would be a good idea to apply a Global Interceptor
for this scenario, like so (shortened version):
@Injectable()
export class EtagInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, call$: Observable<any>): Observable<any> {
// get the request and log it to the console
const ctx = context.switchToHttp();
const request = ctx.getRequest();
const response = ctx.getResponse();
// the etag a client sends to the API
const requestETag = request.header('if-none-match');
return call$.pipe(
map((content) => {
// calculate the etag of the current answer
const responseETag = crypto.createHash('md5').update(JSON.stringify(content)).digest('hex');
// and append it to the response
response.setHeader('etag', responseETag);
// both etags (request and calculated response) are identical
// set the appropriate Http Status 304 (NOT MODIFIED)
// and remove the content;
if (requestETag === responseETag) {
response.status(304); // <-- this does not work!
content = '';
}
return content;
}),
);
}
}
So for my use-case, how is it not possible to set the status code?
I read the answer from above:
- sometimes response status codes are dependent on exceptions and exception filters are executed after interceptors,
- global response controller's logic is the last step performed just before sending a final result through the network (that's the place where default status codes come in).
Unfortunately, both points make no sense to me:
1) I can set the status to 304 (NOT MODIFIED)
in an interceptor. If, however, at any later stage of the execution, something fails, the status code may be overwritten by an Exception / Error
2) Wouldn't it be better to set the default value for the Response
first and then let everyone overwrite it as the request is processed?
All the best and thank you so much for this awesome framework!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Dear all,
i recently stumbled upon the same problem, that i want to modify the HTTP Status Code in an interceptor. Consider the following example:
I created an
ETagInterceptor
that calculates theEtag
of the response to be send back to my client. If the client makes another request to my API, he may send his etag viaif-none-match
http header to the API. The API then processes the request and creates the response. If the new etag matches theif-none-match
header, the content shall be removed (i.e,. set to''
) and the server must return withhttp code 304 (NOT MODIFIED)
.I thought it would be a good idea to apply a
Global Interceptor
for this scenario, like so (shortened version):So for my use-case, how is it not possible to set the status code?
I read the answer from above:
Unfortunately, both points make no sense to me:
1) I can set the status to
304 (NOT MODIFIED)
in an interceptor. If, however, at any later stage of the execution, something fails, the status code may be overwritten by anException / Error
2) Wouldn't it be better to set the default value for the
Response
first and then let everyone overwrite it as the request is processed?All the best and thank you so much for this awesome framework!