快速开始 Quick Start

导读

利用 TypeScript 和 GraphQL 的强大功能

GraphQL 是一种强大的 API 查询语言,也是使用现有数据执行这些查询的运行时。它是一种优雅的方法,可以解决 REST API 中常见的许多问题。作为背景介绍,我们建议阅读 GraphQL 和 REST 之间的 比较。GraphQL 与 TypeScript 相结合,可帮助您通过 GraphQL 查询实现更好的类型安全性,从而为您提供端到端的类型输入。

在本章中,我们假设您对 GraphQL 有基本的了解,并重点介绍如何使用内置的 @nestjs/graphql 模块。 GraphQLModule 可以配置为使用 Apollo 服务器(使用 @nestjs/apollo 驱动程序)和 Mercurius(使用 @nestjs/mercurius)。我们为这些经过验证的 GraphQL 软件包提供官方集成,以提供一种将 GraphQL 与 Nest 结合使用的简单方法(查看 此处 的更多集成)。

您还可以构建自己的专用驱动程序(阅读更多相关信息,请 此处)。

安装

首先安装所需的软件包:

bash
# For Express and Apollo (default)
$ npm i @nestjs/graphql @nestjs/apollo @apollo/server graphql

# For Fastify and Apollo
# npm i @nestjs/graphql @nestjs/apollo @apollo/server @as-integrations/fastify graphql

# For Fastify and Mercurius
# npm i @nestjs/graphql @nestjs/mercurius graphql mercurius
警告

@nestjs/graphql@>=9@nestjs/apollo^10 软件包与 Apollo v3 兼容(查看 Apollo Server 3 迁移指南 了解更多详情),而 @nestjs/graphql@^8 仅支持 Apollo v2(例如 apollo-server-express@2.x.x 软件包)。

概述

Nest 提供两种构建 GraphQL 应用程序的方法,代码优先架构优先 方法。您应该选择最适合您的方法。本 GraphQL 部分中的大多数章节分为两个主要部分:一个是如果您采用代码优先,则应遵循的部分;另一个是如果您采用模式优先,则应使用的部分。

代码优先方法中,您使用装饰器和 TypeScript 类来生成相应的 GraphQL 模式。如果您更喜欢专门使用 TypeScript 并避免在语言语法之间切换上下文,则此方法很有用。

模式优先方法中,事实来源是 GraphQL SDL(模式定义语言)文件。SDL 是一种与语言无关的方式,用于在不同平台之间共享模式文件。Nest 会根据 GraphQL 模式自动生成您的 TypeScript 定义(使用类或接口),以减少编写冗余样板代码的需要。

开始使用 GraphQL 和 TypeScript

提示

在接下来的章节中,我们将集成 @nestjs/apollo 包。如果您想改用mercurius包,请导航至此部分

安装包后,我们可以导入GraphQLModule并使用forRoot()静态方法对其进行配置。

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

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
    }),
  ],
})
export class AppModule {}
提示

对于 mercurius 集成,您应该改用 MercuriusDriverMercuriusDriverConfig。两者都是从 @nestjs/mercurius 包导出的。

forRoot() 方法将选项对象作为参数。这些选项将传递到底层驱动程序实例(在此处阅读有关可用设置的更多信息:ApolloMercurius)。例如,如果您想禁用 playground 并关闭 debug 模式(对于 Apollo),请传递以下选项:

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

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      playground: false,
    }),
  ],
})
export class AppModule {}

在这种情况下,这些选项将被转发到 ApolloServer 构造函数。

GraphQL 游乐场

游乐场是一个图形化、交互式、浏览器内 GraphQL IDE,默认情况下在与 GraphQL 服务器本身相同的 URL 上可用。要访问游乐场,您需要配置并运行一个基本的 GraphQL 服务器。要立即查看它,您可以安装并构建 此处的工作示例。或者,如果您按照这些代码示例进行操作,一旦您完成了 解析器章节 中的步骤,您就可以访问游乐场。

有了这些,并且您的应用程序在后台运行,您就可以打开 Web 浏览器并导航到 http://localhost:3000/graphql(主机和端口可能因您的配置而异)。然后您将看到 GraphQL 游乐场,如下所示。

![img](/images/playground.png" alt=")

注意

@nestjs/mercurius 集成不随内置的 GraphQL Playground 集成一起提供。相反,您可以使用 GraphiQL(设置 graphiql: true)。

多个端点

@nestjs/graphql 模块的另一个有用功能是能够同时为多个端点提供服务。这让您可以决定哪些模块应该包含在哪个端点中。默认情况下,GraphQL 会在整个应用程序中搜索解析器。要将此扫描限制为模块的子集,请使用 include 属性。

ts
GraphQLModule.forRoot({
  include: [CatsModule],
})
警告

如果您在单个应用程序中将 @apollo/server@as-integrations/fastify 包一起使用,并且有多个 GraphQL 端点,请确保在 GraphQLModule 配置中启用 disableHealthCheck 设置。

代码优先

代码优先 方法中,您使用装饰器和 TypeScript 类来生成相应的 GraphQL 模式。

要使用代码优先方法,首先将 autoSchemaFile 属性添加到选项对象:

ts
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
})

autoSchemaFile 属性值是自动生成的架构的创建路径。或者,可以在内存中即时生成架构。要启用此功能,请将 autoSchemaFile 属性设置为 true

ts
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  autoSchemaFile: true,
})

默认情况下,生成的架构中的类型将按照它们在包含的模块中定义的顺序排列。要按字典顺序对架构进行排序,请将 sortSchema 属性设置为 true

ts
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
  sortSchema: true,
})

示例

此处 提供了完整可用的代码优先示例。

模式优先

要使用模式优先方法,首先向选项对象添加 typePaths 属性。typePaths 属性指示 GraphQLModule 应在何处查找您要编写的 GraphQL SDL 模式定义文件。这些文件将在内存中合并;这允许您将模式拆分为多个文件并将它们放置在解析器附近。

ts
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  typePaths: ['./**/*.graphql'],
})

通常,您还需要具有与 GraphQL SDL 类型相对应的 TypeScript 定义(类和接口)。手动创建相应的 TypeScript 定义是多余且繁琐的。它使我们没有单一的可信来源——在 SDL 中所做的每个更改都迫使我们调整 TypeScript 定义。为了解决这个问题,@nestjs/graphql 包可以从抽象语法树 (AST) 自动生成 TypeScript 定义。要启用此功能,请在配置 GraphQLModule 时添加 definitions 选项属性。

ts
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  typePaths: ['./**/*.graphql'],
  definitions: {
    path: join(process.cwd(), 'src/graphql.ts'),
  },
})

definitions 对象的 path 属性指示将生成的 TypeScript 输出保存在何处。默认情况下,所有生成的 TypeScript 类型都创建为接口。要生成类,请将 outputAs 属性指定为 'class' 的值。

ts
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  typePaths: ['./**/*.graphql'],
  definitions: {
    path: join(process.cwd(), 'src/graphql.ts'),
    outputAs: 'class',
  },
})

上述方法在每次应用程序启动时动态生成 TypeScript 定义。或者,最好构建一个简单的脚本来按需生成这些定义。例如,假设我们创建以下脚本作为generate-typings.ts

ts
import { join } from 'node:path'
import { GraphQLDefinitionsFactory } from '@nestjs/graphql'

const definitionsFactory = new GraphQLDefinitionsFactory()
definitionsFactory.generate({
  typePaths: ['./src/**/*.graphql'],
  path: join(process.cwd(), 'src/graphql.ts'),
  outputAs: 'class',
})

现在您可以按需运行此脚本:

bash
$ ts-node generate-typings
提示

您可以预先编译脚本(例如,使用tsc)并使用node执行它。

要为脚本启用监视模式(每当任何.graphql文件更改时自动生成类型),请将watch选项传递给generate()方法。

ts
definitionsFactory.generate({
  typePaths: ['./src/**/*.graphql'],
  path: join(process.cwd(), 'src/graphql.ts'),
  outputAs: 'class',
  watch: true,
})

要为每个对象类型自动生成附加的 __typename 字段,请启用 emitTypenameField 选项。

ts
definitionsFactory.generate({
  // ...,
  emitTypenameField: true,
})

要将解析器(查询、突变、订阅)生成为不带参数的普通字段,请启用 skipResolverArgs 选项。

ts
definitionsFactory.generate({
  // ...,
  skipResolverArgs: true,
})

Apollo Sandbox

要使用 Apollo Sandbox 而不是 graphql-playground 作为用于本地开发的 GraphQL IDE,请使用以下配置:

ts
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'
import { Module } from '@nestjs/common'
import { GraphQLModule } from '@nestjs/graphql'
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      playground: false,
      plugins: [ApolloServerPluginLandingPageLocalDefault()],
    }),
  ],
})
export class AppModule {}

示例

此处 提供了一个完全可用的架构优先示例。

访问生成的架构

在某些情况下(例如端到端测试),您可能希望获取对生成的架构对象的引用。在端到端测试中,您可以使用 graphql 对象运行查询,而无需使用任何 HTTP 侦听器。

您可以使用 GraphQLSchemaHost 类访问生成的架构(采用代码优先或架构优先方法):

ts
const { schema } = app.get(GraphQLSchemaHost)
提示

您必须在应用程序初始化后(在 onModuleInit 钩子被 app.listen()app.init() 方法触发后)调用 GraphQLSchemaHost#schema getter。

异步配置

当您需要异步传递模块选项而不是静态传递时,请使用 forRootAsync() 方法。与大多数动态模块一样,Nest 提供了几种处理异步配置的技术。

一种技术是使用工厂函数:

ts
GraphQLModule.forRootAsync<ApolloDriverConfig>({
  driver: ApolloDriver,
  useFactory: () => ({
    typePaths: ['./**/*.graphql'],
  }),
})

与其他工厂提供程序一样,我们的工厂函数可以是 异步,并且可以通过 inject 注入依赖项。

ts
GraphQLModule.forRootAsync<ApolloDriverConfig>({
  driver: ApolloDriver,
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    typePaths: configService.get<string>('GRAPHQL_TYPE_PATHS'),
  }),
  inject: [ConfigService],
})

或者,您可以使用类而不是工厂来配置 GraphQLModule,如下所示:

ts
GraphQLModule.forRootAsync<ApolloDriverConfig>({
  driver: ApolloDriver,
  useClass: GqlConfigService,
})

上面的构造在 GraphQLModule 中实例化 GqlConfigService,并使用它来创建选项对象。请注意,在此示例中,GqlConfigService 必须实现 GqlOptionsFactory 接口,如下所示。GraphQLModule 将在所提供类的实例化对象上调用 createGqlOptions() 方法。

ts
@Injectable()
class GqlConfigService implements GqlOptionsFactory {
  createGqlOptions(): ApolloDriverConfig {
    return {
      typePaths: ['./**/*.graphql'],
    }
  }
}

如果您想重用现有的选项提供程序,而不是在 GraphQLModule 中创建私有副本,请使用 useExisting 语法。

ts
GraphQLModule.forRootAsync<ApolloDriverConfig>({
  imports: [ConfigModule],
  useExisting: ConfigService,
})

Mercurius 集成

Fastify 用户(阅读更多 此处)可以使用 @nestjs/mercurius 驱动程序,而不是使用 Apollo。

ts
import { Module } from '@nestjs/common'
import { GraphQLModule } from '@nestjs/graphql'
import { MercuriusDriver, MercuriusDriverConfig } from '@nestjs/mercurius'

@Module({
  imports: [
    GraphQLModule.forRoot<MercuriusDriverConfig>({
      driver: MercuriusDriver,
      graphiql: true,
    }),
  ],
})
export class AppModule {}
提示

应用程序运行后,打开浏览器并导航到 http://localhost:3000/graphiql。您应该会看到 GraphQL IDE

forRoot() 方法将选项对象作为参数。这些选项将传递到底层驱动程序实例。有关可用设置的更多信息,请参阅 此处

第三方集成

示例

一个工作示例可在此处找到 此处