加入我们,于10月8日至10日前往纽约市,学习关于GraphQL联盟和API平台工程的最新技巧、趋势和新闻。加入我们,共同参加2024年纽约市的GraphQL峰会
文档
免费开始

解析器

Apache Server如何处理GraphQL操作


需要知道如何为您的模式中的每个填充数据,以便它可以响应该数据的请求。为此,它使用

解析器是一个负责填充您的模式中单个字段数据的函数。它可以在您定义的任何方式中填充数据,例如从后端数据库或第三方API获取数据。

如果您没有为特定的定义解析器,Apollo Server会自动为其定义默认的默认解析器

定义解析器

基本语法

假设我们的服务器定义如下(非常短的)模式

type Query {
numberSix: Int! # Should always return the number 6 when queried
numberSeven: Int! # Should always return 7
}

我们想要为 resolvers 定义 numberSixnumberSeven Query 类型,以便它们在查询时始终返回 67

这些 resolvers 定义看起来是这样的:

const resolvers = {
Query: {
numberSix() {
return 6;
},
numberSeven() {
return 7;
},
},
};

如这个示例所示

  • 在下面的例子中,你将定义服务器所有的 resolvers 在一个单个的 JavaScript 对象中(如上方的 resolvers 所示)。这个对象被称为 解析器映射
  • 解析器映射具有顶层 字段,这些字段对应于您的架构类型(如 Query 上方所示)。
  • 每个 解析器 函数属于其对应字段所属的类型。

处理参数

假设我们的服务器定义了如下架构:

type User {
id: ID!
name: String
}
type Query {
user(id: ID!): User
}

我们想要能够查询 user 字段并按 id 获取用户。

为了实现这一点,我们的服务器需要访问用户数据。在这个假设的例子中,假定服务器定义了以下硬编码数组

const users = [
{
id: '1',
name: 'Elizabeth Bennet',
},
{
id: '2',
name: 'Fitzwilliam Darcy',
},
];

现在我们可以定义一个 解析器 用于 user 字段,如下所示:

const resolvers = {
Query: {
user(parent, args, contextValue, info) {
return users.find((user) => user.id === args.id);
},
},
};

如这个示例所示

  • 一个解析器可以可选地接受四个位置参数(parent, args, contextValue, info).
  • 这里的 args 是一个对象,它包含为 GraphQL 查询中 提供的所有 的参数。

注意,这个示例未为 没有 定义 User 字段(idname 的解析器。那是因为 Apollo Server 为这些字段创建的默认解析器做对了:它直接从 user 解析器返回的对象中获取值。

将解析器传递给 Apollo Server

注意

在下面的示例中,我们使用顶层 await 调用来异步启动我们的服务器。如果您想了解我们如何设置它,请查看 入门指南 以获取详细信息。

在定义了所有的解析器之后,将它们传递给 ApolloServer 构造函数(作为 resolvers 属性),同时携带你的模式定义(作为 typeDefs 属性)。

以下示例定义了一个硬编码的数据集、一个模式和解析器映射。然后初始化一个 ApolloServer 实例,并传入模式和解析器。

请注意,您可以像您想要的那样将您的resolvers定义在不同的文件和对象中,只要将它们合并到单个 resolver map 中,然后传递给ApolloServer构造函数。

Resolver chains

每次查询要求返回一个object typefield时,查询也会要求该对象的至少一个字段(如果没有,则没有理由在查询中包含该对象)。查询总是“到底”字段的,这些字段返回一个标量,一个枚举或这些列表之一。

例如,此Product类型的所有field都会“到底”:

type Product {
id: ID!
name: String
variants: [String!]
availability: Availability!
}
enum Availability {
AVAILABLE
DISCONTINUED
}

由于这个规则,每当 Apollo Server解析返回对象类型的field时,它总是会然后解析该对象的一个或多个字段。这些子字段反过来也可能会包含object type。根据您的模式,这种对象-field 调用模式可以继续到一个任意深度,创建一个称为resolver chain的结构。

示例

假设我们的服务器定义了以下模式

# A library has a branch and books
type Library {
branch: String!
books: [Book!]
}
# A book has a title and author
type Book {
title: String!
author: Author!
}
# An author has a name
type Author {
name: String!
}
type Query {
libraries: [Library]
}

以下是对该模式的有效查询:

query GetBooksByLibrary {
libraries {
books {
author {
name
}
}
}
}

此查询的结果 resolver chain 与查询本身的层次结构相匹配:

Query.libraries()
Library.books()
Book.author()
Author.name()

这些 resolver 以上述顺序执行,并将它们的返回值通过parent参数传递给链中的下一个 resolver。

以下是一个代码示例,该示例使用此 resolver chain 解析上述查询:

如果我们现在更新我们的query以便也要求每本书的title

query GetBooksByLibrary {
libraries {
books {
title
author {
name
}
}
}
}

那么 resolver chain 看起来是这样的:

Query.libraries()
Library.books()
Book.title()
Book.author()
Author.name()

当一个链“发散”像这样时,每个子链都会并行执行。

Resolver arguments

函数接受四个参数parent, args, contextValueinfo(按此顺序)。

您可以在代码中为每个参数使用任何名称,但Apollo文档使用这些名称作为规范。除了parent之外,也可以使用父类型的名称或source

参数描述
parent

此字段父(即此字段上一个)的 resolver 的返回值。

对于没有父的顶层字段(如Query resolver),此值从传递给Apollo Server 构造函数的rootValue函数中获取。

args

一个对象,其中包含为此字段提供的所有 GraphQL arguments

例如,当执行query{ user(id: "4") }时,传递给user resolver 的args对象是{ "id": "4" }

contextValue

一个对象,在整个特定操作的所有 resolver 中共享。

使用它来共享每个操作的状态,包括身份验证信息、dataloader 实例以及其他可以在 resolver 之间跟踪的内容。

info

包含关于操作执行状态的信息,包括字段名称、从根到字段的路径等。

它的核心字段列在GraphQL.js 源代码中。 Apollo Server 通过添加一个cacheControl字段来扩展它。

contextValue参数

解reader �永远不会对contextValue参数进行破坏性修改。这确保了所有resolver之间的一致性,并防止了意外的错误。

您的 resolver 可以通过它们的第三个位置参数访问共享的contextValue对象。contextValue对象对所有在特定操作中执行的 resolver 都是可访问的:

import { UserAPI } from './datasources/users';
const resolvers = {
Query: {
// Our resolvers can access the fields in contextValue
// from their third argument
currentUser: (_, __, contextValue) => {
return contextValue.dataSources.userApi.findUser(contextValue.token);
},
},
};
interface MyContext {
// Context typing
token?: String;
dataSources: {
userApi: UserAPI;
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
context: async ({ req }) => ({
token: getToken(req.headers.authentication),
dataSources: {
userApi: new UserAPI(),
},
}),
});
import { UserAPI } from './datasources/users';
const resolvers = {
Query: {
// Our resolvers can access the fields in contextValue
// from their third argument
currentUser: (_, __, contextValue) => {
return contextValue.dataSources.userApi.findUser(contextValue.token);
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
context: async ({ req }) => ({
token: getToken(req.headers.authentication),
dataSources: {
userApi: new UserAPI(),
},
}),
});

要了解如何管理数据库和其他的连接,请参阅数据抓取

有关更多信息,请参见共享上下文

返回值

Apollo Server根据返回值的类型处理解析器函数的返回值:

类型描述
标量/对象

解析器可以返回单个值或对象,如定义解析器中所示。此返回值通过parent参数将传递给任何嵌套解析器。

数组

如果您的schema指示解析器相关联的字段包含列表,则返回一个数组。

返回数组后,Apollo Server为数组中的每个项目执行嵌套解析器。

null / undefined

表示无法找到字段的值。

如果您的schema指示此解析器的字段可为null,那么操作结果在该字段的位置有一个null值。

如果此解析器的字段不可为null,Apollo Server将该字段的父级设置为null。

Promise

可以是异步的,并执行异步操作,例如从数据库或后端API抓取。为了支持这一点,解析器可以返回一个解析为任何其他支持的返回类型的Promise。

默认解析器

如果您未为特定schema字段定义解析器,Apollo Server为它定义一个默认解析器。

默认解析器函数使用以下逻辑:

N
Yes
N
Yes
Does the parent argument have a
property with this resolver's exact name?
Return undefined
Is that property's value a function?
Return the property's value
Call the function and
return its return value

例如,考虑以下schema摘录:

type Book {
title: String
}
type Author {
books: [Book]
}

如果为 books 字段的解析器返回一个包含 title 字段的每个对象的数组,则您可以使用 title 字段的默认解析器。默认解析器将正确返回 parent.title

解析联合和接口

有一些 GraphQL 类型允许您定义一个返回多种可能的对象类型的字段(即,联合和接口)。为了解析可以返回不同对象类型的字段,您必须定义一个 __resolveType 函数来通知 Apollo Server 返回的对象类型。

解析联邦实体

请参阅 解析实体

监控解析器性能

与所有代码一样,解析器的性能取决于其逻辑。了解您模式中哪些字段计算量较大或解析速度较慢非常重要,这样您就可以提高它们的性能或确保仅在需要时查询它们。

Apollo Studio可以与 Apollo Server 直接集成,提供字段级指标,帮助您了解图形随时间推移的性能。有关更多信息,请参阅 分析性能

上一页
指令
下一页
共享上下文
评分文章评分在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,商用名为Apollo GraphQL。

隐私政策

公司