Kotlin で GraphQL のクエリを生成する DSL
Kotlin DSL を利用して GraphQL のクエリを生成したいという気持ちがありました.
調べてみると, 特定のスキーマに対しての DSL を実装してみた, みたいなことをやっている方はいそうです. しかし, 実際に使われているような API についてガッチリ実装したものは見当たりません.
また, VerachadW/kraph のように, 汎用的に使えるようにした実装も存在します. とはいえやはり, Kotlin の DSL で書きたい, という気持ちを満たすにはちょっと違うなと感じますし, そもそも記述量が増えるだけで現実的なメリットもなさそうです.
GraphQL のクエリの見た目なるべくそのままで, Kotlin の世界でクエリを書けるようなものが欲しいと思いました.
アイデア
- 特定のスキーマ定義だけではなく汎用的に使えるようにしたい
- 安全で IDE での補完がきくようにしたい(文字列でフィールドを指定みたいなアプローチではなく)
なので, 一つのアプローチとして以下のような方針が考えられました.
GraphQL API スキーマ定義
↓
(変換)
↓
API のための DSL 定義の Kotlin コード
↑
アプリケーションコードから呼び出す
実装した
前述の方針で実装してみたものが以下です.
例えば, 以下のようなスキーマ定義があるとき,
type Query {
books: [Book!]!
authors: [Author!]!
}
type Book {
title: String!
author: Author!
}
type Author {
firstName: String!
lastName: String!
books: [Book!]!
}
生成された DSL 定義を利用すると以下のようなコードを書くことができます.
@Test
fun query() {
val q = query {
books {
title
author {
firstName
lastName
}
}
}
val expected = """
query {
books {
title
author {
firstName
lastName
}
}
}
""".trimIndent()
val actual = formatQuery(q.toString()) // formatQuery just makes it look good
assertThat(actual).isEqualTo(expected)
}
実例
実際に GitHub の GraphQL API のスキーマから生成した DSL がこちらです.
少なくとも現状ではコンパイルが通り利用可能なコードが生成されています.
というか, 有名かつ大規模で実際にユーザーに利用されている GraphQL API として, GitHub の API から生成できるところを最初のゴールにしていたのですが…
問題とか
結局のところ, レスポンスのための型も自動生成できないと嬉しくないわけで, これだけだと実用性はないだろうと思います.
クラス定義からクエリを生成する, みたいなアプローチになるのももっともだなと改めて理解しました.