15. Mutation 输入
5m

概述

让我们完成我们的!

在本课中,我们将

  • 了解 参数的常见约定和input 类型
  • 了解如何使用 响应来处理成功和失败的操作

Mutation 参数和输入

我们之前在 中使用过 Query.playlist — 我们传递了一个名为 id

GraphQL Schema
type Query {
playlist(id: ID!): Playlist
}

对于 addItemsToPlaylist ,我们需要不止一个

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

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

我们 可以 将所有三个都用作 ,但将 input 类型 用作 是最佳实践。

input 类型中, 是一个特殊的 ,它将一组 组合在一起,然后可以用作另一个 的参数。

作为命名约定,我们在类型名称后添加 Input 后缀,并为它赋予与它关联的 相同的名称。

在我们的例子中,我们可以将 命名为 AddItemsToPlaylistInput 作为 。让我们开始创建它吧!

The AddItemsToPlaylistInput 类型

让我们创建一个名为 add_items_playlist_input.py 的新文件,放在 api/types 文件夹下,并定义一个名为 AddItemsToPlaylistInput 的类。

api/types/add_items_to_playlist_input.py
import strawberry
class AddItemsToPlaylistInput:
...

我们还需要使用 input 类型来定义这个类,使用 @strawberry.input 装饰器。与我们迄今为止使用过的其他 Strawberry 函数类似,我们可以为这个函数提供 namedescription ,在 中使用。

让我们将 @strawberry.input 装饰器应用到这个类上。

api/types/add_items_to_playlist_input.py
@strawberry.input
class AddItemsToPlaylistInput:
...

接下来,我们将添加属性。请记住,我们至少需要播放列表的 ID 和 URI 列表。我们 可以 也指定将这些项目添加到播放列表中的位置,但这对于 REST API 来说不是必需的。默认情况下,曲目将被追加到播放列表的末尾,因此我们可以从我们的 中省略它。请记住,你的 GraphQL API 不需要完全匹配你的 REST API!

api/types/add_items_to_playlist_input.py
playlist_id: strawberry.ID = strawberry.field(description="The ID of the playlist.")
uris: list[str] = strawberry.field(description="A list of Spotify URIs to add.")

更新解析器

现在,让我们确保我们的 了解这个输入。回到 api/mutation.py 中,我们可以将其添加到函数的参数中。我们将这个 命名为 input

注意, input 参数可以命名为 任何 东西,例如 playlist_trackstracks_input !我们建议与你的团队协商确定命名约定。使用 input 作为 名称是一个常见的约定。

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

既然我们已经在这里,让我们也使这个函数成为异步的,并添加 info 参数。我们稍后将需要它来访问 spotify_client

api/mutation.py
async def add_items_to_playlist(
self,
input: AddItemsToPlaylistInput,
info: strawberry.Info
) -> AddItemsToPlaylistPayload:
...

现在,让我们使用我们的服务和输入类型!在 函数的主体中,我们将使用 add_tracks_to_playlist.asyncio 方法来调用我们的 mock_spotify_rest_api_client 包。

api/mutation.py
client = info.context["spotify_client"]
await add_tracks_to_playlist.asyncio(
playlist_id=input.playlist_id, uris=",".join(input.uris), client=client
)

以方法签名为指南,我们可以从 input 中添加对应值到 playlist_iduris。对于最后一个参数,我们需要稍微调整一下格式。由于 input.uris 是一个 list 类型的 str,而方法期望的是一个以逗号分隔的值的 str 类型,所以我们将使用 ",".join

这只是我们正在使用的 REST 端点的性质。要检索 playlist 对象,我们需要使用之前用过的 get_playlist 方法进行后续调用。

但是我们应该在哪里进行调用呢?如果将它包含在这个 resolver 中,那么即使 playlist 字段没有包含在 GraphQLmutation 中,也意味着需要进行额外的 REST 调用!

我们之前已经遇到过这种情况,当时我们使用了 resolver 链。然而,在这种情况下,我们将保持 REST 调用包含在这个 resolver 中。从客户端应用程序的需求角度考虑,如果它们要向播放列表添加曲目,它们很 可能 会将播放列表及其曲目列表包含在 GraphQL 操作中!他们想要看到他们 结果mutation 毕竟。

让我们继续。在 add_items_to_playlist 解析器中,我们将调用 get_playlist 函数。

api/mutation.py
data = await get_playlist.asyncio(playlist_id=input.playlist_id, client=client)
playlist = Playlist(id=data.id, name=data.name, description=data.description)

看起来眼熟吧?这是我们在 Query.playlist 解析器中使用的代码。

最后,让我们更新 AddItemsToPlaylistPayload 实例中的返回值,具体来说是将硬编码的播放列表替换为 playlist 变量。

api/mutation.py
return AddItemsToPlaylistPayload(
code=200,
success=True,
message="Successfully added items to playlist.",
playlist=playlist,
)

成功路径已经处理好了!现在如果发生错误怎么办?让我们将到目前为止的代码包装在 try 块和 except 任何被抛出的 Exception 中。

api/mutation.py
try:
await add_tracks_to_playlist.asyncio(
playlist_id=input.playlist_id, uris=",".join(input.uris), client=client
)
data = await get_playlist.asyncio(playlist_id=input.playlist_id, client=client)
playlist = Playlist(id=data.id, name=data.name, description=data.description)
return AddItemsToPlaylistPayload(
code=200,
success=True,
message="Successfully added items to playlist.",
playlist=playlist,
)
except Exception as e:
...

如果出现错误,我们的返回值应该略有不同。我们仍然会返回 AddItemsToPlaylistPayload 类型,但这次代码将是 500,成功状态将是 false,并且我们将返回异常的任何消息。 playlist 参数将设置为 None

api/mutation.py
return AddItemsToPlaylistPayload(
code=500,
success=False,
message=str(e),
playlist=None,
)

最后,不要忘记文件开头需要的所有导入

api/mutation.py
from .types.add_items_to_playlist_input import AddItemsToPlaylistInput
from mock_spotify_rest_api_client.api.playlists import (
add_tracks_to_playlist,
get_playlist,
)

探索时间!

在服务器运行最新的更改后,让我们开始一个新的工作区标签,从头开始构建我们的 mutation。随着 input 参数的添加,当我们添加 addItemsToPlaylist 字段时, GraphQL 操作看起来有点不同:

https://127.0.0.1:8000

Explorer - AddItemsToPlaylist mutation

GraphQL 操作
mutation AddItemsToPlaylist($input: AddItemsToPlaylistInput!) {
addItemsToPlaylist(input: $input) {
}
}

我们也可以看到 Variables 部分中有一个 input 属性在 JSON 对象中:

Variables
{
"input": null
}

让我们开始填写这个 input 对象。在 Documentation 面板中,点击 input 字段,并添加来自 AddItemsToPlaylistInput 的三个字段。Explorer 会自动更新你的 variables

https://127.0.0.1:8000

Explorer - AddItemsToPlaylist mutation adding variables for input

Variables
{
"input": {
"playlistId": null,
"uris": null
}
}

我们只需要更新这些 null!我们将使用一个新的播放列表 ID,并在其中添加一个包含一个 URI 的数组。这些都是模拟数据,所以你可以在里面放任何你想要的作为占位符。它不需要实际存在于 Spotify 数据库中。

Variables
{
"input": {
"playlistId": "6LB6g7S5nc1uVVfj00Kh6Z",
"uris": ["ASongAboutGraphQL"]
}
}
https://127.0.0.1:8000

Explorer - AddItemsToPlaylist mutation adding variables for input

最后,让我们填写 mutation 的其余部分,包括我们需要的字段。添加 codesuccessmessage 字段。然后对于播放列表,添加其详细信息 以及 其曲目!

GraphQL 操作
mutation AddItemsToPlaylist($input: AddItemsToPlaylistInput!) {
addItemsToPlaylist(input: $input) {
code
message
success
playlist {
id
name
tracks {
id
name
}
}
}
}

这是一个巨大的 mutation,按下播放按钮运行!我们应该看到我们的数据成功返回。在 tracks 列表的底部,我们将看到 id 设置为我们传递给 uri 变量,以及名称。

https://127.0.0.1:8000

Explorer - AddItemsToPlaylist mutation adding variables for input

注意:你的响应看起来有点不同吗?因为 REST API 在所有 Odyssey 学习者之间共享,你可能会在你的响应中看到更多或更少的曲目。这很可能是因为 其他 学习者向播放列表添加了自己的曲目。我们也会定期重置数据以保持数据的干净。

太棒了!现在看看如果你将播放列表 ID 更新为一个不存在的值会发生什么。

Variables
{
"input": {
"playlistId": "DoesNotExist",
"uris": ["ASongAboutGraphQL"]
}
}
https://127.0.0.1:8000

Explorer - AddItemsToPlaylist mutation adding variables for input

当我们再次运行 mutation 时,我们仍然会收到数据,但这次我们得到了一个错误代码、一条失败消息和一个 null 播放列表。

我们的 mutation 正在工作! 🎉

练习

我们如何在模式中使用 input 类型?
在为 mutation 创建 input 类型时,通常使用什么命名约定?

关键要点

  • GraphQL 中, Mutations 通常需要多个参数来执行操作。为了将参数分组在一起,我们使用 GraphQL input 类型来提高清晰度和可维护性。
  • Strawberry 使用 @strawberry.input 将 Python 类标记为 GraphQL input 类型。
  • 我们可以像访问任何其他 GraphQL 参数一样,在解析器函数中访问 input 参数。

结论

太棒了,你做到了,你构建了一个 API!你现在拥有一个可用的 ,它塞满了使用 Spotify REST API 作为 的播放列表和曲目。你已经编写了查询和 ,并且在此过程中学习了一些常见的 GraphQL 约定。你已经探索了如何在你的架构设计中使用 GraphQL 和输入类型。花点时间庆祝一下;这可是学到了很多东西啊!

如果你有任何关于你想看到下一步内容的请求,请在下方告诉我们!

上一页

分享你对本节课的疑问和评论

本课程目前处于

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

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