如何在Nestjs代码优先中设置Apollo的cacheControl指令

问题描述 投票:0回答:1

我正在尝试在某些字段上设置静态缓存控件,如此处

所做的那样

根据我的理解,我需要使用指令,因此我使用以下嵌套文档来声明指令

所以,我构建了一个cacheControl指令,这就是我的GraphQLModule.forRootAsync在buildSchemaOptions中的内容:

buildSchemaOptions: {
        directives: [
          new GraphQLDirective({
            name: 'cacheControl',
            locations: [
              DirectiveLocation.FIELD_DEFINITION,
              DirectiveLocation.OBJECT,
              DirectiveLocation.INTERFACE,
              DirectiveLocation.UNION
            ],
            args: {
              maxAge: { type: GraphQLInt },
              scope: {
                type: new GraphQLEnumType({
                  name: 'CacheControlScope',
                  values: {
                    PUBLIC: {
                      astNode: {
                        kind: 'EnumValueDefinition',
                        description: undefined,
                        name: {
                          kind: 'Name',
                          value: 'PUBLIC'
                        },
                        directives: []
                      }
                    },
                    PRIVATE: {
                      astNode: {
                        kind: 'EnumValueDefinition',
                        description: undefined,
                        name: {
                          kind: 'Name',
                          value: 'PRIVATE'
                        },
                        directives: []
                      }
                    }
                  }
                })
              },
              inheritMaxAge: { type: GraphQLBoolean }
            }
          })
        ]
      } 

它确实在模式中创建了指令:

directive @cacheControl(maxAge: Int, scope: CacheControlScope, inheritMaxAge: Boolean) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION

enum CacheControlScope {
  PUBLIC
  PRIVATE
}

现在,我尝试在 @ObjectType 中的字段声明中使用它,如下所示:

import { Directive, Field, Int, ObjectType } from '@nestjs/graphql'

@ObjectType('User')
export class User {
  @Directive('@cacheControl(maxAge:60)')
  @Field(() => Int)
  id!: number

  @Directive('@cacheControl(maxAge:60)')
  @Field()
  text!: string
}

但是当执行一些查询来获取所有用户时,它似乎没有缓存任何内容 - 并且不发送缓存控制标头并每次执行整个查询。 我尝试做一个转换器,但不确定如何为解析器实现缓存。 我错过了什么?

graphql nestjs code-first apollo-server cache-control
1个回答
0
投票

我能够在 NestJS 中实现此功能。关键是确保任何子对象类型也指定了

maxAge
或设置了
inheritMaxAge: true
。这对于解析器
Query
ResolveField
来说是一样的。

代码:

app.module.ts

import { ApolloServerPluginCacheControl } from '@apollo/server/plugin/cacheControl';
import responseCachePlugin from '@apollo/server-plugin-response-cache';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule, Int } from '@nestjs/graphql';
import { DirectiveLocation, GraphQLBoolean, GraphQLDirective, GraphQLEnumType } from 'graphql';

import { ParentResolver } from './parent.resolver';

@Module({
    imports: [
        GraphQLModule.forRoot<ApolloDriverConfig>({
            driver: ApolloDriver,
            autoSchemaFile: true,
            plugins: [ApolloServerPluginCacheControl(), responseCachePlugin()],
            buildSchemaOptions: {
                directives: [
                    new GraphQLDirective({
                        name: 'cacheControl',
                        args: {
                            maxAge: { type: Int },
                            scope: {
                                type: new GraphQLEnumType({
                                    name: 'CacheControlScope',
                                    values: {
                                        PUBLIC: {},
                                        PRIVATE: {},
                                    },
                                }),
                            },
                            inheritMaxAge: { type: GraphQLBoolean },
                        },
                        locations: [
                            DirectiveLocation.FIELD_DEFINITION,
                            DirectiveLocation.OBJECT,
                            DirectiveLocation.INTERFACE,
                            DirectiveLocation.UNION,
                            DirectiveLocation.QUERY,
                        ],
                    }),
                ],
            },
        }),
    ],
    providers: [ParentResolver]
})
export class AppModule {}

cache-control.decorator.ts

import { Field, ObjectType, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';

import { CacheControl } from './cache-control.decorator';

@ObjectType()
export class ParentSchema {
    @Field()
    field: string;
}

@ObjectType()
export class ChildSchema {
    @Field()
    field: string;
}

@Resolver(() => ParentSchema)
export class ParentResolver {
    @CacheControl({ maxAge: 100 })
    @Query(() => Parent, { name: 'parent' })
    async getParent(): Promise<ParentSchema> {
        return {
            field: 'field-a',
        };
    }

    // need to make sure that the child field also specifies cache control settings
    @CacheControl({ inheritMaxAge: true })
    @ResolveField('child', () => ChildSchema)
    async getChild(): Promise<ChildSchema> {
        return { field: 'field-b' };
    }
}

parent.resolver.ts

import { Field, ObjectType, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';

import { CacheControl } from './cache-control.decorator';

// cache control hints can be applied to types
@CacheControl({ maxAge: 100 })
@ObjectType()
export class ParentSchema {
    @Field()
    foo: string;
}

// need to make sure child types also specify cache control hints
@CacheControl({ inheritMaxAge: true })
@ObjectType()
export class ChildSchema {
    @Field()
    bar: string;
}

@Resolver(() => ParentSchema)
export class ParentResolver {
    // OR cache control hints can be applies to resolvers
    @CacheControl({ maxAge: 100 })
    @Query(() => Parent, { name: 'parent' })
    async getParent(): Promise<ParentSchema> {
        return {
            foo: 'biz',
        };
    }

    // need to make sure that the child field also specifies cache control hints
    @CacheControl({ inheritMaxAge: true })
    @ResolveField('child', () => ChildSchema)
    async getChild(): Promise<ChildSchema> {
        return { bar: 'baz' };
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.