Christophe Blin
Christophe Blin

Reputation: 1909

NestJs Apollo GraphQL federation and responseCachePlugin

I'd like to cache my expensive GQL queries on the server-side with nestjs

I've followed https://docs.nestjs.com/graphql/plugins#using-external-plugins and then https://www.apollographql.com/docs/apollo-server/performance/caching/#caching-with-responsecacheplugin-advanced

I've also seen https://github.com/nestjs/graphql/issues/443#issuecomment-599445224 which suggests that it should work as expected

I am using apollo federation

the problem I have is that it works (more or less) correctly if I add the responseCachePlugin inside the subgraph

However, when I try to use the responseCachePlugin at the gateway (i.e at the federation service), it simply is ignored: all the requests always hit the downstream subgraphs

package.json

"dependencies": {
    ...
    "@nestjs/common": "^7.6.18",
    "@nestjs/core": "^7.6.18",
    "@nestjs/graphql": "^7.11.0",
    "@nestjs/platform-express": "^7.6.18",
    "apollo-server-express": "^2.25.0",
    "apollo-server-plugin-response-cache": "^0.9.0",
    ...
    "graphql": "^15.5.0",
    "graphql-subscriptions": "^1.2.1",
    "graphql-type-json": "^0.3.2",
    ...
}

Note : using 0.9.0 to be compatible with 2.25.0 (not yet the possibility to move to latest 3.2.0)

Then, in my "main" module of the gateway I have :

GraphQLGatewayModule.forRootAsync({
      imports: [
        LoggerModule,
        BuildServiceModule,
        ConfigModule.register(GwEnvVar, GW_DEFAULT_CONFIG),
      ],
      inject: [ConfigService, GATEWAY_BUILD_SERVICE],
      useFactory: (configService: ConfigService<GwEnvVar>) => ({
        cors: true,
        server: {
          introspection:
            configService.env.NODE_ENV === NodeEnv.PRODUCTION ? false : true,
          playground: true,
          cacheControl: {
            defaultMaxAge: 5,
          },
          plugins: [responseCachePlugin()],
        },
        gateway: getSupergraphSchema('schema.gql', configService.env),
      }),
    }),
  ],
})
export class GraalModule {}

The app starts correctly but, as I already said, every request hit the downstream subgraphs

Also note that if I put the exact same config directly in subgraphs, then the resolvers are not hit anymore (however, it means the cache is done inside the subgraph which is NOT what I'd like)

If not providing directly a solution, does anyone have a pointer to explain how caching is supposed to work with apollo federation (beyond the minimalist doc https://www.apollographql.com/docs/apollo-server/performance/caching/#caching-with-responsecacheplugin-advanced and https://www.apollographql.com/docs/federation/performance/caching/) ?

Upvotes: 2

Views: 1878

Answers (1)

nthurnau
nthurnau

Reputation: 45

I was having a similar problem (without federation) and found the following additions need to be made:

  • you need to install apollo-cache-control in addition to apollo-server-plugin-response-cache when you are not using apollo server v3+.
  • you need to add @cacheControl to the type's fields if they're also types, and they have to match the parent. Otherwise the cache control maxAge will use the defaultMaxAge. For example:
    type Dog @cacheControl(maxAge: 100) {
        dob: String,
        name: String,
        breed: Breed
    }
    type Breed @cacheControl(maxAge: 100) {
        name: String!
        size: Int
    }

Upvotes: 0

Related Questions