14. 突变响应
5m

概述

到目前为止,我们只使用了一种类型的 :查询。 这些是用于检索数据的只读操作。 要修改数据,我们需要使用另一种类型的 GraphQL 操作: ,这是写操作。

在本课中,我们将学习有关设计 和突变响应的常见约定

突变

接下来是 MusicMatcher 项目中的下一个功能:将曲目添加到现有播放列表中。

让我们看一下启用此功能的相应 REST API 方法POST /playlists/{playlist_id}/tracks.

https://spotify-demo-api-fe224840a08c.herokuapp.com/v1/docs

Mock REST API with POST endpoint

从文档中,我们需要以下参数:

  • playlist_id - 播放列表的 ID,作为 string(必需)
  • position - 一个 integer,从零开始的索引,我们想要插入曲目(们)的位置
  • uris - 一个以逗号分隔的 string,其中包含我们要添加的曲目的 uri

然后,该方法将返回一个包含 snapshot_id 属性的对象,该属性表示播放列表在该时间点的状态。

好的,现在如何在 中启用此功能?

设计突变

让我们从我们的模式开始。

对于 名称,我们建议以描述我们更新操作的特定动作的动词开头(例如添加、删除或创建),然后是突变作用于的数据。

对于 的返回类型,我们可以返回 突变作用于的对象。 但是,我们建议遵循一致的 Response 类型用于 响应。

突变响应

我们需要考虑可能发生的任何部分错误并向客户端返回有用的信息。 我们建议在所有 响应中添加三个常见的

  • code:一个 int,它指的是响应的状态,类似于 HTTP 状态码。
  • success:一个 bool 标志,指示 负责的所有更新是否成功。
  • message:一个 string,用于显示有关 结果的客户端信息。 如果突变仅部分成功,并且通用错误消息无法说明全部情况,这将特别有用。

然后,我们还将有一个 用于我们正在突变的 Playlist,在本例中)。 在某些 中,这可能是 多个 对象!

至于命名约定,返回类型通常以 PayloadResponse 结尾。

AddItemsToPlaylistPayload 类型

遵循我们介绍的最佳实践,我们将为我们的 命名为 AddItemsToPlaylist。 让我们首先创建此 的返回类型: AddItemsToPlaylistPayload

api/types 下,我们将创建一个名为 api/types/add_items_to_playlist_payload.py 的新文件。

在内部,我们将创建 AddItemsToPlaylistPayload 类,应用 @strawberry.type 装饰器。

api/types/add_items_to_playlist_payload.py
import strawberry
@strawberry.type
class AddItemsToPlaylistPayload:
...

然后,我们将为 codesuccessmessage 添加属性。

api/types/add_items_to_playlist_payload.py
code: int = strawberry.field(description="Similar to HTTP status code, represents the status of the mutation.")
success: bool = strawberry.field(description="Indicates whether the mutation was successful.")
message: str = strawberry.field(description="Human-readable message for the UI.")

在本例中,我们正在突变的对象是 Playlist 类型,它是可为空的,因为突变可能会出错!

api/types/add_items_to_playlist_payload.py
playlist: Playlist | None = strawberry.field(description="The playlist that contains the newly added items.")

我们还需要在文件顶部导入 Playlist 类型:

api/types/add_items_to_playlist_payload.py
from .playlist import Playlist

一个新的入口点:Mutation

api 下,我们将创建一个名为 mutation.py 的新文件。 在此文件中,我们将定义一个名为 Mutation 的新类:

api/mutation.py
import strawberry
@strawberry.type
class Mutation:
...

接下来,我们将为我们的 函数编写 AddItemsToPlaylist 。 它将返回 AddItemsToPlaylistPayload 类型。 我们也将为它添加一个描述。

我们将函数保持在 Pythonic snake_case 中,但请记住,Strawberry 会自动将它转换为模式中的 camelCase

api/mutation.py
def add_items_to_playlist(self) -> AddItemsToPlaylistPayload:
...

为了将其定义为一个 ,我们通常使用 @strawberry.field 装饰器,但这次我们将使用一个新函数: strawberry.mutation

strawberry.mutation 定义了用于 mutation。它的工作方式与 strawberry.field 相同。我们可以将其用作装饰器,并提供 描述。

api/mutation.py
@strawberry.mutation(description="Add one or more items to a user's playlist.")
def add_items_to_playlist(self) -> AddItemsToPlaylistPayload:
...

我们现在将硬编码 的结果。小步走!我们将创建一个新的 AddItemsToPlaylistPayload 实例,将 200 传递给 code,将 true 传递给 success 状态,传递一个成功的 message 和一个硬编码的 Playlist 对象。

api/mutation.py
return AddItemsToPlaylistPayload(
code=200,
success=True,
message="Successfully added items to playlist.",
playlist=Playlist(
id="6Fl8d6KF0O4V5kFdbzalfW",
name="Sweet Beats & Eats",
description=None,
),
)

最后,我们将导入 AddItemsToPlaylistPayloadPlaylist 类型,位于文件顶部:

api/mutation.py
from .types.add_items_to_playlist_payload import AddItemsToPlaylistPayload
from .types.playlist import Playlist

我们的 需要了解这个新的架构入口点。就像 Query 类型一样,我们需要在架构中设置 类型。

打开 api/schema.py 文件,并在顶部导入 Mutation 类。

api/schema.py
from .mutation import Mutation

然后,我们将它传递给 strawberry.Schema

api/schema.py
schema = strawberry.Schema(query=Query, mutation=Mutation)

保存所有这些更改并重启服务器。

探索时间!

是时候试试我们的 了!回到 Sandbox Explorer,我们将创建一个新的工作区选项卡。

Documentation 面板中,让我们导航回到架构的根目录。在 Query 旁边,我们可以看到 Mutation 类型。

https://127.0.0.1:8000

Explorer - mutation added

让我们添加 addItemsToPlaylist 以及其中的所有子字段。对于 playlist,现在选择 name

GraphQL 操作
mutation AddItemsToPlaylist {
addItemsToPlaylist {
code
message
success
playlist {
name
}
}
}

运行

https://127.0.0.1:8000

Explorer - mutation response

响应数据
{
"data": {
"addItemsToPlaylist": {
"code": "200",
"message": "Added items to playlist successfully",
"success": true,
"playlist": {
"name": "Sweet Beats & Eats"
}
}
}
}

就像 响应一样,我们的 响应也遵循与 mutation 相同的形状!

练习

根据上面推荐的约定,以下哪些是 mutation 的好名称?
在 mutation 响应类型(AddItemsToPlaylistPayload)中,为什么修改后的对象的返回类型(Playlist)是可空的?

关键要点

  • 是写入 ,用于修改数据。
  • 命名 通常以一个描述动作的动词开头,例如 "add"、"delete" 或 "create"。
  • 创建一致的 响应类型是一个常见的约定。

下一步

我们将学习 输入和返回真实数据的最佳实践。

上一个

分享您关于本课程的问题和评论

本课程目前处于

测试版
.您的反馈有助于我们改进!如果您遇到困难或困惑,请告诉我们,我们将帮助您解决。所有评论都是公开的,必须遵守 Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。

您需要一个 GitHub 帐户才能在下方发布。还没有? 改为在我们的 Odyssey 论坛中发布。