GraphQLサーバを作る際には graphql-java-tools
を使うと便利らしいので使ってみました。
graphql-java-tools について
graphql-java
だけでは冗長になりがちな仕組みを提供してくれるライブラリみたいです。すでにプロジェクトで独自のドメイン似特化したPOJOがある場合に、GraphQLとシームレスに統合できるようになっているんだとか。Javaとライブラリ名にありますが、JVM上なら動作するためKotlinでも使うことができるみたいですね。
GraphQLは関連するライブラリが多いように感じます。Qiitaのこの記事にそれぞれのライブラリの関連性が書かれています。この記事によれば graphql-java-tools
はGraphQL関連に関して graphql-java
のみに依存しているみたいです。
queryの実装
動作環境は以下の通りです。
> java -version java version "1.8.0_191" Java(TM) SE Runtime Environment (build 1.8.0_191-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode) > gradle -version ------------------------------------------------------------ Gradle 6.0.1 ------------------------------------------------------------ Build time: 2019-11-18 20:25:01 UTC Revision: fad121066a68c4701acd362daf4287a7c309a0f5 Kotlin: 1.3.50 Groovy: 2.5.8 Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019 JVM: 1.8.0_191 (Oracle Corporation 25.191-b12) OS: Mac OS X 10.15.3 x86_64
graphql-java-tools
を試すに当たり、 graphql-spring-boot
を使用することにしました。このライブラリは graphql-java-tools
も含んでいるのでこちらのライブラリだけを依存先に追加するだけでよいみたいです。 build.gradle.kts
の全文は最後の補足に乗せてあります。
GraphQLスキーマは以下になります。
type Query { bookMarks: [BookMark!]! } type BookMark { title: String! url: String! }
上記のスキーマに合わせてQueryの実装をしていくのですが、graphql-java-tools
では Resolver
というクラスをGraphQLスキーマに対応付けします。 簡単に Resolver
の立ち位置をスケッチしてみました。
Queryでは GraphQLQueryResolver
インターフェイスを継承したResolverクラスをGraphQLスキーマに対応付けます。bookMarks()
メソッドはGraphQLスキーマの bookMarks: [BookMark!]!
に対応しています。この仕組があることで、GraphQLスキーマとそれを処理する実装の紐づきが明確になっているように感じます。
package demo.tools.graphql import com.coxautodev.graphql.tools.GraphQLQueryResolver import org.springframework.stereotype.Component @Component class Query(val bookMarkRepository: BookMarkRepository) : GraphQLQueryResolver { fun bookMarks(): List<BookMark> { return bookMarkRepository.getAll() } }
この Query
クラスを使ってGraphQLインスタンスを生成すれば実装は終わりです。 以下のコードではSchemaParser.newParser()
によってGraphQLインスタンスを生成しています。これも graphql-java-tools
による機能です。 上記の Query
クラスは resolvers()
メソッドで渡します。
package demo.tools.graphql import com.coxautodev.graphql.tools.GraphQLMutationResolver import com.coxautodev.graphql.tools.GraphQLQueryResolver import com.coxautodev.graphql.tools.SchemaParser import graphql.GraphQL import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.context.annotation.Bean @SpringBootApplication class DemoApplication { @Bean fun graphQL(query: GraphQLQueryResolver): GraphQL { val graphQLSchema = SchemaParser.newParser() .file("schema.graphqls") .resolvers(query) .build() .makeExecutableSchema() return GraphQL.newGraphQL(graphQLSchema).build() } } fun main(args: Array<String>) { runApplication<DemoApplication>(*args) }
mutationの実装
mutationも上記のやり方とほとんど同じです。 Query
の代わりに Mutation
クラスを作り、登録します。
まずはGraphQLSchemaにMutationを追加します。
type Query { bookMarks: [BookMark!]! } type Mutation { registerBookMark(title: String, url: String): BookMark! } type BookMark { title: String! url: String! }
次に対応する Mutation
クラスを実装します。
package demo.tools.graphql import com.coxautodev.graphql.tools.GraphQLMutationResolver import org.springframework.stereotype.Component @Component class Mutation(val bookMarkRepository: BookMarkRepository) : GraphQLMutationResolver { fun registerBookMark(title: String, url: String): BookMark { val aNewBookMark = BookMark(title, url) bookMarkRepository.save(aNewBookMark) return aNewBookMark } }
最後に Query
を作成したときと同様、 GraphQL
インスタンスに Mutation
インスタンスを登録します。
エンドポイントを叩いてみる
実際にサーバーに対してリクエストを投げてみました。リクエスト・レスポンスの送受信には GraphQL IDE を使いました。
では、Mutationによって BookMark
を登録してみます。
// リクエスト mutation registerBookMark($title: String, $url: String) { registerBookMark(title: $title, url: $url) { title url } } { "title": "demoo", "url": "http://demo.com" }
// レスポンス { "data": { "registerBookMark": { "title": "demoo", "url": "http://demo.com" } } }
Query で全件取得をしてみます。
// リクエスト { bookMarks { title url } }
// レスポンス { "data": { "bookMarks": [ { "title": "google", "url": "https://google.com" }, { "title": "demoo", "url": "http://demo.com" } ] } }
補足
今回使用したプロジェクトの build.gradle.kts
は以下になります。
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("org.springframework.boot") version "2.2.4.RELEASE" id("io.spring.dependency-management") version "1.0.9.RELEASE" kotlin("jvm") version "1.3.61" kotlin("plugin.spring") version "1.3.61" } group = "com.graphql-java.tutorial" version = "0.0.1-SNAPSHOT" java.sourceCompatibility = JavaVersion.VERSION_1_8 repositories { mavenCentral() } dependencies { implementation("com.graphql-java-kickstart:graphql-spring-boot-starter:6.0.0") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") } tasks.withType<Test> { useJUnitPlatform() } tasks.withType<KotlinCompile> { kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") jvmTarget = "1.8" } }