加入我们,从 10月8日至10日,在纽约市学习有关 GraphQL 联邦和 API 平台工程的最新技巧、趋势和新闻。加入我们,在纽约市的 2024 年 GraphQL 大会
文档
免费开始

从GraphQL模式生成类型

如何确保您的解析器类型安全


👋 如果您还没有设置使用 Apollo Server 的 TypeScript项目,请继续阅读我们的入门指南

使用一个 来清晰定义每种类型及 可用的数据。基于此模式,类型生成库可以自动根据该模式生成 TypeScript 类型。

您可以使用由这些生成的 TS 类型在你的 中进行类型检查,以确保解析器返回值的类型与模式中指定的 字段类型一致。对解析器进行类型检查可以帮助您快速捕获错误,并让您相信类型安全可以确保错误的无缝处理。

想要为您的 Apollo Federation 打印子图 的类型?我们的 子图模板 铺垫可以帮助您快速设置带有生成类型的

设置您的项目

我们将使用 GraphQL Code Generator 库基于我们的 GraphQL方案 来生成类型。为 GraphQL Code Generator 提供模式有多种方式。下面,我们将介绍最常见的方法,该方法需要我们的方案存储在 .graphql 文件中。

如果您还没有做的话,请将服务器方案移动到 .graphql 文件,如下所示:

schema.graphql
type Query {
books: [Book]
}
type Book {
title: String
author: String
}
type AddBookMutationResponse {
code: String!
success: Boolean!
message: String!
book: Book
}
type Mutation {
addBook(title: String, author: String): AddBookMutationResponse
}

如果您已将模式移动到一个 .graphql 文件中,请更新导入以确保您仍然正确地将模式传递给服务器。在创建服务器的文件中,您可以使用 readFileSyncfs 包读取模式:

src/index.ts
// ...other imports
import { readFileSync } from 'fs';
// Note: this uses a path relative to the project's
// root directory, which is the current working directory
// if the server is executed using `npm run`.
const typeDefs = readFileSync('./schema.graphql', { encoding: 'utf-8' });
interface MyContext {
dataSources: {
books: Book[];
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
// ... start our server

重新启动您的服务器以确保它可以找到和使用您的模式,以及确保一切按预期工作。接下来,我们将安装生成类型所需的包。

安装和配置依赖项

运行以下命令,将 @graphql-codegen/cli@graphql-codegen/typescript@graphql-codegen/typescript-resolvers 包安装到项目的开发依赖项中:

npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers

关于上述每个软件包的更多信息,请查看GraphQL Code Generator文档。

接下来,我们将设置一个配置文件来告诉GraphQL Code Generator如何在何处以及如何生成类型。您可以通过手动创建一个codegen.yml文件或通过使用以下命令来完成,该命令将指导您完成此过程:

npx graphql-code-generator init

以下是一个codegen.yml文件的示例:

# This configuration file tells GraphQL Code Generator how
# to generate types based on our schema.
schema: "./schema.graphql"
generates:
# Specify where our generated types should live.
./src/__generated__/resolvers-types.ts:
plugins:
- "typescript"
- "typescript-resolvers"
config:
useIndexSignature: true
# More on this below!
contextType: "../index#MyContext"

查看文档以了解更多关于上述配置选项的信息。

最后,我们建议您添加有助于您的package.json文件中添加有用的脚本,以确保您的 TS 类型定期生成:

{
// ...
"scripts": {
"generate": "graphql-codegen --config codegen.yml",
"compile": "npm run generate && tsc",
"start": "npm run compile && node ./dist/index.js",
},
// ...
}

我们还推荐添加脚本以监视您的代码, 启用您的类型在您工作后台进行再生,以及重新编译TypeScript文件。

以上,运行npm start命令根据我们的GraphQL模式生成类型,并编译我们的TypeScript代码。第一次运行graphql-codegen命令时,您将在codegen.yml文件中指定的路径看到充满生成类型的文件。

向解析器添加类型

typescript-resolvers插件创建了一个Resolvers类型,您可以使用它将类型添加到您的解析器映射中,确保您的解析器的返回值与模式中指定的字段类型匹配。

Resolvers类型导入到您定义解析器的文件中:

resolvers.ts
// This is the file where our generated types live
// (specified in our `codegen.yml` file)
import { Resolvers } from './__generated__/resolvers-types';

现在,您可以直接将Resolvers类型添加到您的映射中:

export const resolvers: Resolvers = {}

您的解析器现在可以对每个解析器的参数和返回值进行类型检查,以匹配模式:

export const resolvers: Resolvers = {
Query: {
// TypeScript now complains about the below resolver because
// the data returned by this resolver doesn't match the schema type
// (i.e., type Query { books: [Book] })
books: () => {
return "apple";
},
},
}

如果你的解析器分布在多个文件中,你可以将这些解析器生成的对应类型提取到这些文件中。例如,下面,我们将生成的类型导入到我们为查询和的单独文件中:

resolvers/queries.ts
import { QueryResolvers } from '__generated__/resolvers-types';
// Use the generated `QueryResolvers`
// type to type check our queries!
const queries: QueryResolvers = {
// ...queries
};
export default queries;
resolvers/mutations.ts
import { MutationResolvers } from '__generated__/resolvers-types';
// Use the generated `MutationResolvers` type
// to type check our mutations!
const mutations: MutationResolvers = {
// ...mutations
};
export default mutations;

解析器上下文类型

您还可以配置 GraphQL 代码生成器,以便为您的解析器共享的上下文添加一个类型,确保 TypeScript 在您尝试使用不存在值时发出警告。

为此,您必须首先将传递给 的接口导出为一个泛型类型参数,用于您的上下文值类型:

src/index.ts
export interface MyContext {
dataSources: {
books: Book[];
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});

还记得我们上面的 contextType 吗?您可以像下面这样将导出的上下文接口传递给 contextType 配置选项:

# ...
config:
useIndexSignature: true
# Providing our context's interface ensures our
# context's type is set for all of our resolvers.
# Note, this file path starts from the location of the
# file where you generate types.
# (i.e., `/src/__generated__/resolvers-types.ts` above)
contextType: "../index#MyContext"

一旦重新生成您的类型,您的上下文值现在在所有的 resolvers 中都将自动进行类型化:

const resolvers: Resolvers = {
Query: {
// Our third argument (`contextValue`) has a type here, so we
// can check the properties within our resolver's shared context value.
books: (_, __, contextValue) => {
return contextValue.dataSources.books;
},
},
}

基本可运行示例

查看我们使用 Apollo 服务器和生成的类型在 CodeSandbox 上的示例:

Edit server-generated-types-as4

有关其支持的特性和集成方法的进一步指导,请查看 GraphQL 代码生成器的文档

上一页
请求格式
下一页
模拟
评价文章评价在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,商号 Apollo GraphQL。

隐私政策

公司