frontpage-android-app を作りつつ apollo-android の実装を紐解く

qiita.com

この記事は GraphQL Advent Calendar の 14 日目です。 サーバサイドや Web フロントの話が続いていますが、今回は Android のお話です。

おなじみの apollographql organization では、frontpage-ios-app という Hello World する人向けのリポジトリが公開されています。

github.com

f:id:rnitame:20181211230103p:plain
frontpage-ios-app を立ち上げた画面

で、Android 版は?と思い探してみたところ、見当たらなかったので今回実装してみました。

その実装を使いながら、Apollo Client の Android 向けの実装である、apollo-android の実装を読み解いて行こうと思います。

github.com

環境

  • apollo-android 1.0.0-alpha3
  • Kotlin 1.3.0

完成版のリポジトリは ↓

github.com

frontpage-android-app 実装

サーバー側を準備

github.com

サーバ側も organization で公開されているため、これを使います。

README にあるとおり、

git clone https://github.com/apollostack/frontpage-server
cd frontpage-server
npm install
npm start

をすると、 http://localhost:8080/graphql でサーバが立ち上がります。

.graphql を書く

github.com

このプラグインの力を借りながら書いていきます。

今回のリポジトリでは、共通部分を Fragment として切り分けて Kotlin 側でも型として引っ張れるようにしています。こんな感じ ↓

         getAuthor(authorId)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeBy(
                    onSuccess = {
                        val author = it.fragments().authorFragment() // Fragment 
                        AlertDialog.Builder(this)
                            .setTitle("Author of the post is ${author.firstName()} ${author.lastName()}.")
                            .setMessage("Posts count: ${author.posts()?.size}")
                            .setCancelable(true)
                            .show()
                    },

また、1 ファイルにまとめて書くと見にくくなるため、Fragment に該当するものはファイル化しました。

apollo-android の rxjava-support で API を叩く

 implementation "com.apollographql.apollo:apollo-rx2-support:1.0.0-alpha3" 

このライブラリを導入することで RxJava を使って API を叩くことが出来ます。実際には以下のように書きます。

   Rx2Apollo.from(apolloClient.query(PostsQuery.builder().build()))
            .map { it.data()?.posts()!! }
            .singleOrError()

PostsQuery は先ほど書いた graphql ファイルに準じた Java ファイルが生成されているので、それを見に行ってくれます。

ここまでできればあとは Android のお作法通りに書くだけです。PostsQuery でリストを取得できるので、それを RecyclerView で表示しました。

f:id:rnitame:20181213235442p:plain

はい、できました!これを使って apollo-android の実装を見ていきます。

apollo-android でできること、今回触れる箇所

Android 寄り

まずは Android 特有のことがらについて。

OkHttp の機能

ApolloClient が OkHttpClient を持つため、OkHttp でできることは全てできます。お好みの Interceptor 入れ放題で、Stetho や Chunk もちゃんとうごきます。

https://github.com/apollographql/apollo-android/blob/master/apollo-runtime/src/main/java/com/apollographql/apollo/ApolloClient.java#L267-L275

RxJava との連携

先ほども書いたとおり、該当するライブラリを入れるだけです。中では ApolloCall (ApolloClient の Callback)をラップしています。

https://github.com/apollographql/apollo-android/blob/master/apollo-rx2-support/src/main/java/com/apollographql/apollo/rx2/Rx2Apollo.java

GraphQL 寄り

次に GraphQL 特有のことがらについて。

apollo-tooling によって生成されたファイルを使った通信

apollo-android に内包されている Gradle タスクでは apollo-codegen を使っていますが、これは Deprecated になっています。(Issue は立ってて対応中)。 このツールが必要な Java ファイルを生成してくれますが、中では JSON をパースしているようです。

github.com

https://github.com/apollographql/apollo-tooling/tree/master/packages/apollo-codegen-core/src

Query, Mutation, Fragment の書き方

apollo-android では、デフォルトでは Query であれば末尾に Query と付ける必要があります。(例:PostsQuery)これを書かなくてもよくなる設定もあるので、お好みで。

スキーマをチームで共有して進める開発の仕方(動画参照)もありますが、大体の場合は各クライアントごとで個別のスキーマを持つことが多いかなと思います。 無限ループになるような Fragment の指定はできないので、それぞれの Query や Mutation で必要な値を指定すると良いです。

(自分が担当してるサービスでは、必要最低限の値を取れる Fragment とすべて取ってくる Fragment を用意して、使い分けていたりします。)

www.youtube.com

まとめと今回触れなかった部分について

apollo-android は頻繁にアップデートがされているのと、雑に issue を作ってもすぐに返答が返ってきます。周辺ツールも整いつつあるので、とても楽にアプリ実装できる状態になってきました。

issue を眺めていると、Coroutine 対応の issue があがっていたりするので、定期的に watch するとおもしろそうです。

github.com

また今回は盛り込めませんでしたが、subscription がある API であれば Redux っぽくできたりしそうですし、(PayPal さんが移行したっぽい)

今年の re:Invent 内の AWS AppSync の発表では、Android Architecture Components との組み合わせの例が紹介されているようでした。

テストやこの辺の設計話はまたどこかでできればと思っています ( ˘ω˘)

※ 母校の大学のアドベントカレンダーの 14 日目の記事でもありました

qiita.com

おわり。