NestJS 9 GraphQL 中文文档(十八) - 迁移指南

226 阅读2分钟

Nest 最新的版本为V9,较之前的V7/8有不小改动,GraphQL 部分官方文档之前的V8也是本人翻译的,有很多不完善的地方,这次打算重新精细翻译一遍,会持续更新这块内容,并最后贡献给中文文档仓库,为中文社区贡献一份力量。有兴趣的小伙伴记得要关注收藏。本篇为系列文档的最后一篇。

迁移至v10

为了帮助你从@nestjs/graphql 版本9迁移至版本10,本文提供了一套指导规范。这个大版本发布的重点是要提供一个更轻便、与平台无关的核心库。

介绍“驱动程序”包

在最新的版本中,我们决定把@nestjs/graphql包拆分到一些独立的库中,让你在项目中,无论选择使用Apollo(@nestjs/apollo),还是Mercurius(@nestjs/mercurius),亦或其他的GraphQL库都可以。

这意味着现在你必须明确指定你的应用程序将要使用的的驱动程序。

// Before
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';

@Module({
  imports: [
    GraphQLModule.forRoot({
      autoSchemaFile: 'schema.gql',
    }),
  ],
})
export class AppModule {}

// After
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: 'schema.gql',
    }),
  ],
})
export class AppModule {}

插件

Apollo服务插件允许你在响应某些事件中执行自定义的操作。由于这是Apollo独有的功能,所以我们将其从@nestjs/graphql移至新创建的@nestjs/apollo包中,因为你必须更新应用程序中的导入。

// Before
import { Plugin } from '@nestjs/graphql';

// After
import { Plugin } from '@nestjs/apollo';

指令

@graphql-tools/schema包的v8版本中,schemaDirectives 功能已经被新的Schema指令 API取代。

// Before
import { SchemaDirectiveVisitor } from '@graphql-tools/utils';
import { defaultFieldResolver, GraphQLField } from 'graphql';

export class UpperCaseDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field;
    field.resolve = async function (...args) {
      const result = await resolve.apply(this, args);
      if (typeof result === 'string') {
        return result.toUpperCase();
      }
      return result;
    };
  }
}

// After
import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils';
import { defaultFieldResolver, GraphQLSchema } from 'graphql';

export function upperDirectiveTransformer(
  schema: GraphQLSchema,
  directiveName: string,
) {
  return mapSchema(schema, {
    [MapperKind.OBJECT_FIELD]: (fieldConfig) => {
      const upperDirective = getDirective(
        schema,
        fieldConfig,
        directiveName,
      )?.[0];

      if (upperDirective) {
        const { resolve = defaultFieldResolver } = fieldConfig;

        // Replace the original resolver with a function that *first* calls
        // the original resolver, then converts its result to upper case
        fieldConfig.resolve = async function (source, args, context, info) {
          const result = await resolve(source, args, context, info);
          if (typeof result === 'string') {
            return result.toUpperCase();
          }
          return result;
        };
        return fieldConfig;
      }
    },
  });
}

要将此指令实现用于包含@upper指令的schema,请使用transformSchema函数:

GraphQLModule.forRoot<ApolloDriverConfig>({
  ...
  transformSchema: schema => upperDirectiveTransformer(schema, 'upper'),
})

Federation

GraphQLFederationModule已经被相应的驱动程序类替代:

// Before
GraphQLFederationModule.forRoot({
  autoSchemaFile: true,
});

// After
GraphQLModule.forRoot<ApolloFederationDriverConfig>({
  driver: ApolloFederationDriver,
  autoSchemaFile: true,
});

提示 ApolloFeferationDriver类和ApolloFederationDriverConfig都是从@nestjs/apollo包中导出的。

同样的,无需使用专用的GraphQLGatewayModule,只需将适合的驱动程序类传递给你的GraphQLModule设置即可:

// Before
GraphQLGatewayModule.forRoot({
  gateway: {
    supergraphSdl: new IntrospectAndCompose({
      subgraphs: [
        { name: 'users', url: 'http://localhost:3000/graphql' },
        { name: 'posts', url: 'http://localhost:3001/graphql' },
      ],
    }),
  },
});

// After
GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
  driver: ApolloGatewayDriver,
  gateway: {
    supergraphSdl: new IntrospectAndCompose({
      subgraphs: [
        { name: 'users', url: 'http://localhost:3000/graphql' },
        { name: 'posts', url: 'http://localhost:3001/graphql' },
      ],
    }),
  },
});

提示
ApolloGatewayDriver类和ApolloGatewayDriverConfig都是从@nestjs/apollo包中导出的。