Is there a way to insert into the db using either the service or the entity provider from an interceptor, middleware and filter?
I went all day trying to do this from an interceptor and getting errors, then changing the interceptor into a middleware class based, then changing it to a functional middleware... I was all over the place. I can't find documentation on this. Any pointers apprecieted.
#Insert into db from interceptor, middleware or filter
1 messages · Page 1 of 1 (latest)
It's doable. What error were you getting in the interceptor?
I’ll get back to you tomorrow. I deleted the branch and stating from new branch. I soon as I hit the error I’ll update this post. Thanks for prompt response.
Ok I got this working with two interceptors and one filter. requestLoggerInterceptor, responseLoggerInterceptor, and loggerExceptionFilter. All of them are logging to the console and saving the log in the database. I have one question... why when I have an exception, the exception gets saved first in the database and then the requestInterceptor?
You shouldn't need two interceptors for request and response logging, that should be managable by just one.
As for the order of execution, that seems strange. Might be related to how things are written, but without seeing anything it's gonna be hard to say
i figures and the reason is that I'm not awaiting the insert and sometimes one goes after the other
async nature of the operations
expected
Most likely, but I wouldn't be able to say without seeing how you have things written
import the service, creating the payload after the log to the console and this.logEntryService(createLogEntryServiceDto)
it is interesting that you said that I should use two interceptors but they should live in the same file
🤔
I never said you should use two interceptors. I said you could use one to log both the request and response
yeah
Unless they're wildly different processes, it's lumping the logging reponsibility to a single class, right?
And interceptors have a pre-controller and post-controller functionality, so it should be fine to do both there
I didn't know that
interesting
My OgmaInterceptor logs the request metadata such as who made the call, what endpoint, method, timing, and response size, in a single interceptor like this, and has customization to allow for logging extra info as well.
That's essentially what the simple LoggingInterceptor example in the docs shows:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before...');
const now = Date.now();
return next
.handle()
.pipe(
tap(() => console.log(`After... ${Date.now() - now}ms`)),
);
}
}
if I want to try/catch this interceptor just in case some code breaks, you would wrap the whole thing... if so what would you do in the catch to not crash the server?
Or you could let the exception filter take care of it, as interceptor errors (so long as async methods are awaited) traverse to the exception filter
If you don't await them you'll need to use a .catch() to ensure the promise rejection is handled
the thing is that when I don't wrap the interceptor in a try/catch, postman hands waiting for a response
What does your interceptor look like?
oh it was a try/catch in the filter
I removed the try/catch in the filter and now postman get the 500
Then what does the filter look like?
@Catch()
export class LoggerExceptionFilter<T> implements ExceptionFilter {
constructor(private readonly logEntryService: LogEntryService, private readonly jwtService: JwtService) {}
catch(exception: T, host: ArgumentsHost) {
try {
const exceptionObject = Object.assign({}, exception);
const exceptionResponse = exceptionObject['response'] ?? null;
const exceptionStatusCode = exceptionResponse?.statusCode ?? 500;
const ctx = host.switchToHttp();
const req: Request = ctx.getRequest();
const res: Response = ctx.getResponse();
const now = new Date().toISOString();
const adpost = chalk.red('[ADPOST]');
const statusCode = exceptionStatusCode;
const methodAndEndpoint = `[${chalk.yellow(req.method)}] ${statusCode} ${req.originalUrl}`;
const errorPayloadString = `[${chalk.red('ERROR')}] ${JSON.stringify(exception)}`;
const logString = `${adpost} ${now} ${methodAndEndpoint} ${errorPayloadString}`;
console.log(logString);
console.log('statusCode', exception);
const errorPayload = Object.assign({}, exception);
const user = this.jwtService.decode(this.getToken(req)) as User;
const logEntryPayload: CreateLogEntryDto = {
issuer_ip: req.socket.remoteAddress,
level: Log.Level.ERROR,
status_code: statusCode,
method: req.method,
coordinates: null,
endpoint: req.originalUrl,
incoming_payload: null,
error_payload: errorPayload,
user_uuid: user ? user.uuid : null,
email: user ? user.email : null,
role: user ? user.role.value : null,
};
this.logEntryService.create(logEntryPayload);
return res.status(Number(statusCode)).json(exception['response']);
} catch (err) {
console.error(err);
}
}
private getToken(req: Request) {...}
private maskPassword(payload: object) {...});
}
return payload;
}
}
You should make sure that when you catch you still res.send() something back
now is working but that I can't get the exception to get the error object when the error is not and HttpException. That's why I'm trying to Obeject.assign({}, exception);
Question… when you put the response logger in the same interceptor… does the interceptor waits for the handler to finished everything has to do and then able to get the payload going back to the client?
My guess is that the response goes inside the return next()
Anything before the return is pre-controller, anything in the next.handle().pipe() is post-controller
Wow
Got it
If I creat two interceptors, one for logging and another to do something different, when I register them in app.module, both are going to be provide: APP_INTERCEPTOR?
Yep