Strawberry Shake でフラグメントを活用する
Strawberry Shake でフラグメントを活用する
Strawberry Shake は .NET 用の GraphQL クライアントライブラリです。
特徴的なのは、*.graphql
ファイルから関連する型を自動生成しちゃうことです。
公式サイトより引用します。
query GetSessions {
sessions(order: { title: ASC }) {
nodes {
title
}
}
}
このような GraphQL を書いてビルドすると呼び出すのに必要な型を生成します。次のように呼び出すことができます。
var result = await client.GetSessions.ExecuteAsync();
result.EnsureNoErrors();
foreach (var session in result.Data.Sessions.Nodes)
{
Console.WriteLine(session.Title);
}
という大変便利なものです。
詳しい使い方は公式サイトのチュートリアル や Strawberry Shake (.NET) で GraphQL #1 こと始め を参考にしてください。
困った!
GraphQL は自由度が高いせいか Strawberry Shake はそれぞれ別の型を生成します。
次の二つの *.graphql
ファイルはどちらもスピーカーを扱っています。
query GetSessions {
sessions(order: { title: ASC }) {
nodes {
title
speakers {
id
name
}
}
}
}
query GetSpeakers {
speakers {
edges {
node {
id
name
}
}
}
}
両者ともにスピーカーのフィールドは同じものです。ですが、それぞれ型が異なります。今回の場合は、前者は IGetSpeakers_Speakers_Edges_Node
で後者は IGetSessions_Sessions_Nodes_Speakers
となりました。
概念上は同じスピーカーですが、実際には型が違うということで同じメソッドを二つ用意する必要があります。
static string Text(IGetSpeakers_Speakers_Edges_Node speaker)
{
return $"{speaker.Name} ({speaker.Id})";
}
static string Text(IGetSessions_Sessions_Nodes_Speakers speaker)
{
return $"{speaker.Name} ({speaker.Id})";
}
まあ、これくらいなら大したことないんですが、GraphQL を提供しているサービスはもっと複雑で、厄介です。コピペコードの嵐になります。
フラグメントを使おう!
GraphQL にはフラグメントという機能があります。
fragment Speaker on Speaker {
id
name
}
こんな感じで書いておいて、先ほどの *.graphql
で利用します。
query GetSessions {
sessions(order: { title: ASC }) {
nodes {
title
speakers {
...Speaker
}
}
}
}
query GetSpeakers {
speakers {
edges {
node {
...Speaker
}
}
}
}
このようにしても両者の型が異なるのは変わらないのですが、Strawberry Shake はフラグメントを頼りに ISpeaker
インターフェイスを生成し、両者はこのインターフェイスを継承します。
つまり、メソッドは一つで済んじゃうということです。
static string Text(ISpeaker speaker)
{
return $"{speaker.Name} ({speaker.Id})";
}
最後に
Strawberry Shake は便利なのですが、人間から見たら同じ型にしてほしいところを別の型にしてしまいます。弱い型付の言語であればどうとでもなるのですが、.NET のように強い型付の言語では面倒です。
フラグメントで、Strawberry Shake に同じ扱いしてほしいものを指定できるようになります。
また、Strawberry Shake が生成する型の名前はかなり長く、名前もそれほど適切ではないため、コード中に型名を書くと可読性がかなり下がります。複雑な *.graphql
ファイルでは、たとえ使いまわさなくても積極的にフラグメントを活用したほうがよいでしょう。
Discussion