#Using a database connection in Exception filters

1 messages · Page 1 of 1 (latest)

deft stag
#

I'm trying to understand how to pass a database connection to an Exception filter. We log exceptions to our SQL database, so besides logging to console I have to insert the errors in a table.

What i did was write an RpcExceptionFilter, in the constructor I'm using a Logger and a DataSource. When I register the filter I do it in main.ts as:

  const logger = app.get(Logger);
  const ds = // how do I do this?

  app.useGlobalFilters(
    new HttpExceptionFilter(logger, ds),
    new MyRPCExceptionFilter(logger, ds),
  );

for other services in my app I just inject it:

  constructor(
    private readonly logger: Logger,
    @InjectDataSource('datasourcename')
    private readonly dataSource: DataSource,
  ) {}

but I can't do this here as I'm manually instantiating with new. What's the correct way to do this?

dim hatch
#
app.get('datasourcename')
#

the parameter to app.get is the injection token under which the instance is registered. For most providers, it is the class reference itself, for others, it's the thing that goes into the @Inject decorator

deft stag
#

i tried this, but i get Error: Nest could not find gestion element (this provider does not exist in the current context)

#

it works with @Inject with that same name. could it be related to it being in a factory?

dim hatch
#

apparently, the datasource provider is not available directly in the AppModule. To retireve it while disregarding module boundaries, use:

app.get('datasourcename', { strict: false })
#

or import the module that contains datasource direcly in AppModule

#

Another variant in which you wouldn't need to worry about this is binding the filters via

providers: [{
  provide: APP_FILTER,
  useClass: HttpExceptionFilter
}]
deft stag
#

i also tried this, but in this case what fails is the @InjectDatasource 😢

#

let me try it again and see the exact error

dim hatch
#

the reason is that the datasource is not available in the module where you're binding it

deft stag
#

i'm binding it in AppModule

#

i'm also declaring TypeORMModule.forRoot in the imports section

#

i think it's more related to asynchronicity?

#
 TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      name: 'gestion',
      useFactory: async (configService: ConfigService) => ({
        name: 'gestion',
        type: 'mssql',
        host: configService.get('DB_GESTION_HOST'),
        ...etc 
        },
      }),
    }),```
#

since it uses useFactory it's not created yet when the filter is created?

dim hatch
#

No, that doesn't have anything to do with it

#

but apparently the forRoot registration doesn't expose the datasource injection token

#

btw I was mistaken with this: app.get('datasourcename', { strict: false })
The 'datasourcename' is not the actual injection token. It is getDataSourceToken('datasourcename')

#

because @InjectDataSource('xyz') is an alias for @Inject(getDataSourceToken('xyz'))

deft stag
#

let me try that

deft stag
#

yes!!! this worked ``` const app = await NestFactory.create(AppModule);

const ds = app.get(getDataSourceToken('gestion'), { strict: false });

app.useGlobalFilters(
new HttpExceptionFilter(ds),
new MyRPCExceptionFilter(ds),
);