Wednesday, 10 July 2019

How to log final GraphQL-Reponse in Nest.js with injected Service to database

I would like to log a GraphQL-Request and its GraphQL-Response to database for some use cases. So far I have written a GraphQLExtension to access all data I need:

export class LoggingExtension extends GraphQLExtension {
    willSendResponse(data: any): any {
        /*
         * data.graphqlResponse.data   -> equal to { data: {} } of response
         * data.graphqlResponse.errors -> equal to { errors: [] } of response
         * data.context.user           -> Authenticated user (added to context by AuthGuard)
         * data.context.body.query     -> equal to GraphQL-Request
         */
        // Process data and (if necessary) write to database..
        return data;
    }
}

This Extension is integrated by GraphQLModule.forRoot({extensions: ...} inside my AppModule-Definition:

@Module({
  imports: [
    TypeOrmModule.forRoot({/*...*/}),
    GraphQLModule.forRoot({
      autoSchemaFile: 'schema.gql',
      typePaths: ['./**/*.graphql'],
      extensions: [() => new LoggingExtension()],
      context: ({ req }) => ({
        headers: req.headers,
        user: req.user,
        body: req.body
      })
    }),
    /*...*/,
    LogModule // provides and exports injectable LogService
  ],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ]
})
export class AppModule {}

It seems to be that I am not able to to use the @Inject-Decorator in my LoggingExtension-Class because I would have to inject the LogService through its constructor. And unfortunately I am not able to pass the LogService to it during the initialisation of extensions from the GraphQLModule.

Therefore I have implemented alternatively an LoggingInterceptor which should do the same like the extension before. On contrast to extensions interceptors are injectable. So I am able to access my LogService I need to write to database. The only problem is that I can't access the final GraphQL-Response with its data- and error properties. (EDIT: Furthermore I cannot access neither the request-body nor the authenticated user. Solved by @jay-mcdoniel, accessible through GqlExecutionContext.create(context).getContext())

Instead the Interceptor provides the hole data of the processed query with all its resolved properties and the exceptions (in case of errors).

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(tap(
      allData => console.log(allData),
      exception => console.log(exception)));
  }
}

But I want to access the data of the GraphQLResponse. I figured out that the interceptor is called before the extension. So the GraphQLResponse-Object does not seem to exist yet. Its generated after the interceptor gets called.

Any ideas?



from How to log final GraphQL-Reponse in Nest.js with injected Service to database

No comments:

Post a Comment