【GraphQL】boolean以外のvariableの値に応じてfieldを呼ぶか決めたい(できないっぽい)
頭出し
GraphQL APIをバックエンドにしているフロントエンドアプリケーションを開発する際は、gqlリテラルをよく書くかと思います。
普通のユースケースであれば、fieldを書いてcodegen!ってやっていれば特段問題ないかと思います。
ですが、まれに「variableの値に応じてfieldを呼ぶか決めたい」ケースがあるかと思います。
このvariableがboolean型であれば特に問題ありません。
GraphQLではDirectivesがサポートされていて、こんな感じ↓でboolの値をfieldの前(この例で言うとfriendsの@includeの後)につけてあげればOK!
query Hero($episode: Episode, $withFriends: Boolean!) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}
Directivesのドキュメント:https://graphql.org/learn/queries/#directives
@include(if: Boolean) Only include this field in the result if the argument is true.
@skip(if: Boolean) Skip this field if the argument is true.
本題
では、今回のタイトルにあるように、variableがstringやnumberの場合はどうでしょうか?
例えば、friendsフィールドの何人分の友達を取得するか、のargumentとして$withFriendsCount
があるとします。
クエリに$withFriendsCount
というvariableを追加して、$withFriendsCount
が渡された時だけ$withFriendsCount
人分のfriendsフィールドを取得したい(並び順はBackendに任せる想定とします)、逆にvariableを渡さないときはfriendsフィールドを呼ばない、としたい場合はこんな感じ↓に書けるのかな〜と妄想しながらググってみました。
query Hero($episode: Episode, $withFriendsCount: Number) {
hero(episode: $episode) {
name
# こんな感じで条件書けると良いな〜
friends(withFriendsCount: $withFriendsCount) @include(if: $withFriendsCount > 0) {
name
}
}
}
解決方法
残念ながら、上記のように@includeもしくは@skipに条件は書けないようです。
理由
GraphQLはシンプルに設計されているから!
確かに@includeの中に条件を書くのはシンプルでないかもしれない。
GraphQL is designed to be as simple as possible so it doesn't support constructions from programming languages, e.g. comparations.
こちらのissueにてGraphQLのdirectorの人が、「GraphQLではdirectives内での条件分岐コードをサポートしていなく、booleanを複数渡してあげえると良いかもね〜」と仰っています。
(badがthumbs upの倍になっているw)
To answer the question directly - GraphQL does not support conditions like this. Multiple booleans may be a fit for your use case
じゃあどうするの?
解決策1
上記の僕の妄想を現実にするには、booleanのvariableを1個追加してあげればなんとかなりそうです。
query Hero(
$episode: Episode,
# デフォルト値を入れておく
$withFriendsCount: Number = 0,
$shouldCallFriends: Boolean = false) {
hero(episode: $episode) {
name
friends(withFriendsCount: $withFriendsCount) @include(if: $shouldCallFriends) {
name
}
}
}
うーん、、、、variableを1つで収めたいところではありますね。。
解決策2
クエリそのものの設計を見直しましょう!
上記の例だとheroフィールドのargumentにwithFriendsCountを追加して、Backendで値に応じて処理してあげると良さそうです。
参考
Discussion