通过 HTTP 服务
使用 HTTP 服务器响应 GraphQL 请求
GraphQL 规范在发送 API 请求和响应时并不要求特定的客户端-服务器协议,但由于 HTTP 的普适性,它是最常见的选择。在本页中,我们将回顾在设置通过 HTTP 运行的 GraphQL 服务器时应遵循的一些关键准则。
请注意,以下准则仅适用于无状态的查询(query)和变更(mutation)操作。有关通常支持此类请求的传输协议的更多信息,请访问 订阅(Subscriptions)页面。
本页的建议与目前正在开发中的详细 GraphQL-over-HTTP 规范 保持一致。虽然尚未最终定稿,但该规范草案是 GraphQL 客户端和库维护者的单一事实来源,详细说明了如何使用 HTTP 传输来暴露和消费 GraphQL API。与语言规范不同,遵守并非强制性,但大多数实现都在转向这些标准,以最大限度地提高互操作性。
API 端点
HTTP 通常与 REST 相关联,后者以“资源”为核心概念。相比之下,GraphQL 的概念模型是 实体图(entity graph)。因此,GraphQL 中的实体不通过 URL 标识。相反,GraphQL 服务器运行在单个 URL/端点上(通常是 /graphql),针对给定服务的所有 GraphQL 请求都应指向该端点。
身份验证发生的位置
大多数现代 Web 框架使用管道模型,请求通过一组 中间件(也称为 过滤器 或 插件)堆栈进行传递。当请求流经管道时,可以对其进行检查、转换、修改或以响应终止。GraphQL 应该放置在所有身份验证(authentication)中间件之后,以便你可以访问在其他 HTTP 端点处理器中拥有的相同会话和用户信息。
在身份验证之后,服务器在 GraphQL 执行开始之前不应对请求做出任何 授权(authorization) 决策。具体而言,字段级授权应由解析器在 GraphQL 的 ExecuteRequest() 过程中调用的业务逻辑来强制执行,从而在引发授权相关错误时能够生成部分响应。
请求格式
请求头
GraphQL 客户端和服务器应支持 JSON 进行序列化,并可以支持其他格式。客户端还应使用 Accept HTTP 标头指示它们在响应中支持哪些媒体类型。具体而言,客户端应在 Accept 标头中包含 application/graphql-response+json。
如果该标头中未包含编码信息,则将假定为 utf-8。但是,如果客户端在请求中未提供 Accept 标头,服务器可能会返回错误响应。
application/graphql-response+json 在 GraphQL over HTTP 规范草案中有所描述。为了确保兼容性,如果客户端在 2025 年 1 月 1 日之前向旧版 GraphQL 服务器发送请求,则 Accept 标头还应包含 application/json 媒体类型,如下所示:application/graphql-response+json, application/json
方法
你的 GraphQL HTTP 服务器必须处理用于查询(query)和变更(mutation)操作的 HTTP POST 方法,也可以接受用于查询操作的 GET 方法。
POST 请求与主体
标准的 GraphQL POST 请求应将其 Content-type 标头设置为 application/json,并包含以下形式的 JSON 编码主体
{
"query": "...",
"operationName": "...",
"variables": { "myVariable": "someValue", ... },
"extensions": { "myExtension": "someValue", ... }
}query 参数是必需的,将包含 GraphQL 文档的源文本。请注意,这里的 query 一词定义不严:该文档可以包含任何有效的 GraphQL 操作(以及相关的片段)。
operationName、variables 和 extensions 参数是可选字段。仅当 query 文档中存在多个操作时,才需要 operationName。
请注意,如果客户端请求中缺少 Content-type 标头,则服务器应响应 4xx 状态码。与 Accept 标头一样,当未显式提供此信息时,对于具有 application/json 媒体类型的请求主体,将假定使用 utf-8 编码。
GET 请求与参数
接收 HTTP GET 请求时,GraphQL 文档应在查询字符串的 query 参数中提供。例如,如果我们想执行以下 GraphQL 查询
{
me {
name
}
}该请求可以通过 HTTP GET 发送,如下所示
http://myapi/graphql?query={me{name}}查询变量可以作为 JSON 编码的字符串在名为 variables 的额外查询参数中发送。如果查询包含多个命名操作,则可以使用 operationName 查询参数来控制执行哪一个。
选择 HTTP 方法
在为 GraphQL 请求选择 HTTP 方法时,有几点需要考虑。首先,对除 POST 之外的 HTTP 方法的支持将由 GraphQL 服务器自行决定,因此客户端将受限于受支持的谓词。
此外,GET HTTP 方法仅可用于 query 操作,因此如果客户端请求执行 mutation 操作,则必须改用 POST 方法。
当服务器确实支持用于查询操作的 GET 方法时,可能会鼓励客户端利用此选项来促进 HTTP 缓存或内容分发网络 (CDN) 中的边缘缓存。然而,由于复杂操作的 GraphQL 文档字符串可能非常长,查询参数可能会超过浏览器和 CDN 对 URL 长度强加的限制。
在这种情况下,一种常见的方法是服务器使用诸如 持久化文档 (persisted documents)、自动持久化查询 (automatic persisted queries) 或 受信任文档 (trusted documents) 之类的技术来存储识别出的 GraphQL 文档。这允许客户端发送短文档标识符而不是完整的查询文本。
响应格式
请求头
响应类型应为 application/graphql-response+json,但也可以是 application/json 以支持旧版客户端。服务器将在响应的 Content-type 标头中指示媒体类型。它还应指示编码,否则将假定为 utf-8。
主体
无论使用哪种 HTTP 方法发送查询和变量,响应都应以 JSON 格式在请求主体中返回。如 GraphQL 规范中所述,查询可能会产生一些数据和一些错误,这些应在如下形式的 JSON 对象中返回
{
"data": { ... },
"errors": [ ... ],
"extensions": { ... }
}如果没有返回错误,则响应中不得存在 errors 字段。如果错误发生在执行开始之前,则 errors 字段必须包含这些错误,且响应中不得存在 data 字段。extensions 字段是可选的,此处提供的信息由 GraphQL 实现自行决定。
你可以在 响应(Response)页面 上阅读有关符合 GraphQL 规范的响应格式的更多信息。
状态码
如果响应包含 data 键且其值不为 null,则对于 application/graphql-response+json 或 application/json 媒体类型,服务器都应响应 2xx 状态码。即使响应包含错误也是如此,因为 HTTP 尚未有代表“部分成功”的状态码。
对于阻止执行 GraphQL 操作的验证错误,服务器通常会发送 400 状态码,尽管某些旧版服务器在使用 application/json 媒体类型时可能会返回 2xx 状态码。
对于以 application/json 媒体类型响应的旧版服务器,不鼓励对无法执行的有效 GraphQL 请求使用 4xx 和 5xx 状态码,但可以根据实现情况使用。由于关于服务端错误来源的潜在歧义,对于此媒体类型,应改用 2xx 代码。
然而,对于具有 application/graphql-response+json 媒体类型的响应,如果有效的 GraphQL 请求执行失败,服务器将回复 4xx 或 5xx 状态码。
服务器实现
如果你使用 Node.js,我们建议查看 JS 服务器实现列表。
你可以在此处查看以 许多其他语言编写的服务器列表。
总结
回顾通过 HTTP 提供 GraphQL 服务的这些建议:
- 服务器应在验证 GraphQL 请求之前处理用户身份验证;授权应在 GraphQL 请求执行期间在你的业务逻辑中进行
- GraphQL API 暴露在单个端点上,通常以
/graphql结尾 - GraphQL 客户端和服务器应支持 JSON,但也可以支持其他格式
- 客户端应在
Accept标头上指示媒体类型为application/graphql-response+json - GraphQL 请求使用
POSTHTTP 方法发送,但查询操作也可以使用GET方法发送 - 对于
POST请求,客户端还应提供值为application/json的Content-type标头 - 已执行的 GraphQL 操作的完整或部分结果将在 JSON 编码的响应主体的
data键中可用,而有关验证或执行期间引发的任何错误的信息将在errors键中可用 - 失败的有效 GraphQL 操作的响应状态码可能会根据响应指示的媒体类型而有所不同,但任何具有非空
data键的 GraphQL 响应都将提供2xx响应
文件上传
通过将文件包装为 mutation 来处理 GraphQL 中的文件上传。了解将文件处理集成到 API 中的推荐方法。