概述
我们还缺少一些东西:播放列表的曲目 - 我们实际想听的歌曲!
在本课中,我们将
- 创建
Track
类型 - 编写解析器 函数,用于播放列表的曲目
The Track
对象
花点时间研究上面的模型,并开始思考我们需要哪些数据,以及它们可能是什么类型。为了简化操作,我们现在将忽略艺术家信息。
你可能还想查看 GET /playlists/{playlist_id}/tracks
端点,以更好地了解 API 返回的内容以及它们对某些属性的命名。
慢慢来!
当你准备好后,将其与我们的结果进行比较
- 曲目的名称是
string.
- “E” 标签表示曲目是否为显式曲目。我们可以将其设置为
bool
类型,并让客户端使用逻辑来显示“E” 标签或不显示。 - 曲目的持续时间。模型显示的格式为分钟和秒之间用冒号隔开,因此我们可能需要将其设置为
string
类型,或者客户端团队可能希望控制他们自己的格式,我们应该将其作为double
类型返回,持续时间以毫秒为单位。REST 端点返回后者,因此我们现在坚持使用它。 - 虽然模型上没有显示,但为对象设置一个标识符非常有用,因此我们将确保也返回曲目的 ID。
- 有一个选项可以复制曲目链接以与他人共享,以便他们也可以在 Spotify 上打开它。因此,我们可能需要将该链接作为
string
返回。在 REST API 中,他们将此命名为uri
。 - 我们将使所有这些 字段 不可为空,因为 REST API 也这样做。
你的设计可能与我们的略有不同,但考虑到这些部分,让我们继续创建我们的 Track
类!请记住,我们将所有 GraphQL 类型一起组织在 Types
文件夹下。
你应该拥有所需的一切知识,可以尝试自己编写!如果你需要参考,请随意使用下面的内容
namespace Odyssey.MusicMatcher;[GraphQLDescription("A single audio file, usually a song.")]public class Track{[ID][GraphQLDescription("The ID for the track.")]public string Id { get; }[GraphQLDescription("The name of the track.")]public string Name { get; set; }[GraphQLDescription("The track length in milliseconds.")]public double DurationMs { get; set; }[GraphQLDescription("Whether or not the track has explicit lyrics (true = yes it does; false = no it does not OR unknown)")]public bool Explicit { get; set; }[GraphQLDescription("The URI for the track, usually a Spotify link.")]public string Uri { get; set; }public Track(string id, string name, string uri){Id = id;Name = name;Uri = uri;}}
提示:在选择模式中的 字段 名称时,尽量做到描述性且简洁。例如,我们可以选择 duration
作为其中一个 字段 名称。但是,durationMs
对返回以毫秒为单位的格式更具描述性。我们也可以选择 durationInMilliseconds
以便进一步说明。如果我们还想支持返回格式化的字符串,我们可以添加一个名为 durationString
的新 字段。使用 GraphQL 描述也有助于清晰度。 了解有关 Apollo 文档中模式命名约定的更多信息。
不要忘记使用 [GraphQLDescription]
属性向模式添加描述。
将曲目连接到播放列表
在我们的 Track
类全部设置好后,我们现在可以添加期待已久的 tracks
字段 到 Playlist
中。
[GraphQLDescription("The playlist's tracks.")]public List<Track> Tracks { get; set; }
让我们考虑一下这个特定的 解析器 函数。到目前为止,Playlist
类包含简单的属性 解析器(用于 Id
、Name
和 Description
)。请记住,在幕后,Hot Chocolate 将具有 get
访问器的属性转换为 解析器。
我们是否可以对我们的 Tracks
解析器 做同样的事情?好吧,让我们检查一下我们的数据来自哪里。对于下一节,我们强烈建议使用代码编辑器的功能来 Cmd/Ctrl + 点击特定类型以导航到其类型导航!
特定播放列表的详细信息来自 Query.Playlist
解析器 函数,该函数使用 SpotifyService
数据源 方法 GetPlaylistAsync
。
如果我们在我们的 SpotifyService.cs
文件中跟随路径,我们可以看到响应返回一个 SpotifyWeb.Playlist
类型。此类型具有一个名为 Tracks
的属性,类型为 PaginatedOfPlaylistTrack
。PaginatedOfPlaylistTrack
然后具有许多与分页相关的其他属性,以及一个名为 Items
的属性,它是一个 PlaylistTrack
类型的集合。
跟随 that 类型,我们得到更多与播放列表曲目的元数据相关的属性,例如谁添加了它以及何时添加,以及一个名为 Track
的属性,类型为 PlaylistTrackItem
。 Finally,这看起来像我们正在寻找的 Track
信息!在其他属性中,它具有 Id
、Name
、Explicit
、Duration_ms
属性,与我们 our 的 Track
类在我们的 GraphQL 模式 中的属性完全匹配。
哇!所有这些都说明,我们必须深入挖掘几层才能返回我们需要的价值。
但是,我们实际上已经完成了第一级。我们将 SpotifyWeb.Playlist
类型转换成了我们 自己 的 Playlist
类,使用构造函数。
public Playlist(SpotifyWeb.Playlist obj){Id = obj.Id;Name = obj.Name;Description = obj.Description;}
所以我们可以扩展这个构造函数,并使用 SpotifyWeb.Playlist
的 obj
来初始化 Playlist.Tracks
属性 变量。
让我们一步一步来!确保依赖你的代码编辑器的 IntelliSense,以便更好地了解每个级别可用的属性。
在 Playlist(SpotifyWeb.Playlist obj)
构造函数中,我们首先提取分页轨道的集合。
var paginatedTracks = obj.Tracks.Items;
这个 paginatedTracks
变量 目前是一个 SpotifyWeb.PlaylistTrackItem
对象的集合。这非常接近我们需要的!我们需要我们 自己 的 Track
类。这应该是一个熟悉的模式,我们之前已经使用过两次了。
我们将创建一个新的、额外的 Track
构造函数,它接受一个 SpotifyWeb.PlaylistTrackItem
对象,并根据该对象的属性初始化其 字段。跳转到 Track.cs
文件:
public Track(PlaylistTrackItem obj){Id = obj.Id;Name = obj.Name;DurationMs = obj.Duration_ms;Explicit = obj.Explicit;Uri = obj.Uri;}
不要忘记在顶部导入 SpotifyWeb
命名空间,因为 PlaylistTrackItem
来自该包。
using SpotifyWeb;
我们现在可以在我们的 Playlist
构造函数中使用这个 Track
构造函数。我们将遍历这些项目,并返回一个新的集合,从 item.Track
创建一个 Track
实例。
var trackObjects = paginatedTracks.Select(item => new Track(item.Track));
最后,我们将转换为 List
类型,因为这是 Tracks
属性期望的类型。
Tracks = trackObjects.ToList();
将所有内容放在一起,新的扩展 Playlist
构造函数如下所示:
public Playlist(SpotifyWeb.Playlist obj){Id = obj.Id;Name = obj.Name;Description = obj.Description;var paginatedTracks = obj.Tracks.Items;var trackObjects = paginatedTracks.Select(item => new Track(item.Track));Tracks = trackObjects.ToList();}
想要更简洁一点吗?我们可以简化为单行代码
public Playlist(SpotifyWeb.Playlist obj){Id = obj.Id;Name = obj.Name;Description = obj.Description;Tracks = obj.Tracks.Items.Select(item => new Track(item.Track)).ToList();}
探索时间!
写了这么多代码,但我们应该有足够的代码来 查询 播放列表的曲目了!确保我们的服务器正在运行最新的更改。
回到 Explorer 中,让我们在原始 查询 中添加播放列表轨道的 字段。
query GetPlaylistDetails($playlistId: ID!) {playlist(id: $playlistId) {idnamedescriptiontracks {idnamedurationMsexplicituri}}}
将 变量 部分设置为:
{"playlistId": "6Fl8d6KF0O4V5kFdbzalfW"}
哇,这个播放列表有这么多曲目!
另一种途径
那么 featuredPlaylists
路径呢?它是我们架构的另一个入口点,它返回一个 Playlist
类型的列表,然后可以访问其 tracks
字段。让我们试试。
query GetFeaturedPlaylists {featuredPlaylists {idnamedescriptiontracks {idnameexplicituri}}}
当我们运行这个 查询 时,我们得到了一个包含消息“无法为非空字段返回 null”的 errors
数组。糟糕!
关键要点
- 解析器 函数可能涉及遍历多个数据级别,特别是在嵌套对象的情况下。
- 我们建议为架构选择描述性但简洁的 字段 名称。
下一步
让我们调查一下错误的来源,并修复它。
分享你关于本课的问题和评论
本课程目前处于
你需要一个 GitHub 帐户才能在下面发帖。没有吗? 改为在我们 Odyssey 论坛上发帖。