Strawberry Shake (.NET) で GraphQL #5 GraphQL union の利用
Strawberry Shake (.NET) で GraphQL #5 GraphQL union の利用
- Strawberry Shake (.NET) で GraphQL #1 こと始め
- Strawberry Shake (.NET) で GraphQL #2 JetBrains Rider 編
- Strawberry Shake (.NET) で GraphQL #3 Shopify につなぐ
- Strawberr yShake (.NET) で GraphQL #4 GraphQL の型とのマッピングのカスタマイズ
- Strawberry Shake (.NET) で GraphQL #5 GraphQL union の利用
前回は Shopify の GraphQL の型と .NET の型のマッピングについて解説しました。今回は GraphQL の union 型ではまったことをまとめます。
うまくいかなかったケース
GraphQL はとても高機能で、インターフェイスも宣言して利用できます。レスポンスの際は次のようにインターフェイスの実装の型を指定することになります。
次の例は Shopify のカートの行の商品の Variant (色とかサイズなど) の Title
を取得するクエリになります。
query GetCart($id: ID!) {
cart(id: $id) {
lines {
edges {
node {
merchandise {
...on ProductVariant {
title
}
}
}
}
}
}
}
C# のコードからアクセスすると、.NET の対応する型に Title
プロパティが見つかりません。
しかし、デバッガーを利用すると Title
プロパティは存在し、値も入っていました。なんでやねん! と思いました。
GraphQL の merchandise
プロパティの型は Merchandise
となっていますが、次のように宣言されています。
"The merchandise to be purchased at checkout."
union Merchandise = ProductVariant
Merchandise
型は ProductVariant
をとるとなっています。union
は次の例のように、型の候補を書くもののようです。
"The list of possible resources a `MenuItem` can reference.\n"
union MenuItemResource = Article | Blog | Collection | Metaobject | Page | Product | ShopPolicy
今回の例では Merchandise
型は ProductVariant
型しかありませんが、...on ProductVariant
を指定して、ProductVariant
型だったらこうすると記述しています。
Merchandise
にはプロパティはなく、.NET 上の対応する型にも同様にプロパティがないということです。
インターフェイスを利用する
GraphQL の union は Strawberry Shake ではインターフェイスで実現しています。
GraphQL の型 | Strawberry Shake が生成する型 |
---|---|
Merchandise |
IGetCart_Cart_Lines_Edges_Node_Merchandise |
ProductVariant |
IGetCart_Cart_Lines_Edges_Node_Merchandise_ProductVariant |
IGetCart_Cart_Lines_Edges_Node_Merchandise_ProductVariant
型は IGetCart_Cart_Lines_Edges_Node_Merchandise
型を継承していて、Title
プロパティを含んでいます。
ですので、次にように IGetCart_Cart_Lines_Edges_Node_Merchandise_ProductVariant
型にキャストすればいいようです。
foreach (var line in result.Data.Cart.Lines.Edges)
{
var productVariant = (IGetCart_Cart_Lines_Edges_Node_Merchandise_ProductVariant)line.Node.Merchandise;
Console.WriteLine(productVariant.Title);
}
試していませんが、GraphQL インターフェイスも union と同様に .NET インターフェイスの継承関係として実装されているのではないかと思います。
ちょっとカッコよく
キャストはしないといけないんですけど、キャスト自体は隠したいですよね! というわけで。
Strawberry Shake が生成する型は部分型 (partial class
) です。ですので生成された型に対してメソッドを追加することは簡単です。
次のようにします。
// 名前空間は生成された型に合わせる。
namespace SampleApp.GraphQL;
public partial interface IGetCart_Cart_Lines_Edges_Node_Merchandise
{
public IGetCart_Cart_Lines_Edges_Node_Merchandise_ProductVariant? OnProductVariant()
{
return this as IGetCart_Cart_Lines_Edges_Node_Merchandise_ProductVariant;
}
}
これで、次のように GraphQL の ...on ****
に似た形式でコードを書くことができます。
foreach (var line in result.Data.Cart.Lines.Edges)
{
Console.WriteLine(line.Node.Merchandise.OnProductVariant().Title);
}
最後に
GraphQL が初めてで苦労し、Strawberry Shake のような自動生成のタイプは使い始めはいいけどうまくいかない時には調査が大変です。それで苦労しましたが、分かってしまえばたいした話ではないです。一度うまくいけば、「慣れてない GraphQL じゃなくて RESTful API を何で用意してくれないんだ?」から「GraphQL って呼び出し側で微調整がやりやすくて便利だよね」に変わります。
日本語の情報が全くなく、公式サイトもドキュメントが短めでかつ GraphQL 初心者ということで理解できず... 苦労した結果をまとめました。
Discussion