使用apollo在Android中实现GraphQL客户端
首先
我目前正在以娱乐为目的开发Android应用程序,在尝试使用GraphQL与服务器端进行交互时,遇到了一些稍微陈旧的互联网信息,并且在官方页面上也有一些问题,因此我将其作为备忘录记录下来。
服务器端
由于我平时是一名Rails工程师,所以在服务器端使用了Rails。不感兴趣服务器端实现的人可以跳过。
要在Ruby中使用GraphQL,需要使用一个叫做graphql-ruby的gem。只需要将它添加到Gemfile中就可以使用了。
gem 'graphql'
首先,使用rails generate命令生成使用GraphQL所需的各种文件。
rails g graphql:install
在config/routes.rb中添加了与GraphQL相关的端点,同时会生成一个app/graphql目录。还会在app/controllers目录下生成一个用于处理的graphql_controller.rb文件。
另外,在GraphQL的开发中,可以使用一个叫做GraphiQL的执行环境应用程序,它是用JavaScript开发的。我认为在Gemfile中也添加了一个叫做graphiql-rails的gem,它将GraphiQL封装为了一个Rails引擎。从config/routes.rb中添加的以下路由,似乎可以通过/graphiql访问。
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end
可以使用这个进行开发,但当想要连接到正式环境或其他GraphQL终端时,GraphiQL应用程序非常方便。它已经被Electron框架转变为桌面应用程序,所以对于Mac用户来说,
brew cask install graphiql
open /Applications/GraphiQL.app
可以通过安装来完成。我认为安装它会非常方便,因为它在很多方面都很实用。
rails g graphql:object Movie id:ID! url:String! key:String! title:String! description:String! published_at:String
rails g graphql:object Category id:ID! name:String! movies:[Movie]
生成完之后,您也可以直接修改文件。
app/graphql/types/movie_type.rb
app/graphql/types/category_type.rb
这些文件定义了对象。
module Types
class CategoryType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: false
field :movies, [Types::MovieType], null: true do
argument :num, Integer, required: false
end
def movies(num: 8)
object.movies.limit(num)
end
end
end
module Types
class MovieType < Types::BaseObject
field :id, ID, null: false
field :url, String, null: false
field :key, String, null: false
field :status, String, null: false
field :title, String, null: false
field :description, String, null: false
field :published_at, String, null: false
end
end
module Types
class QueryType < Types::BaseObject
field :category, CategoryType, null: true do
argument :id, ID, required: true
end
def category(id:)
Category.find(id)
end
end
end
我快速地准备了服务器端的工作。虽然这次我使用了Rails进行开发,但您可以根据自己的喜好选择合适的工具来进行实现。
Android方面
当在Android应用中调用API时,以前RESTful API通常使用库如Retrofit2。GraphQL虽然在获取信息时也使用POST方法,但最初我认为可以通过Retrofit2实现POST。然而,在GraphQL中,许多人使用名为apollo的库。这次我也使用了apollo来实现GraphQL客户端的实现。
关于使用方面,Apollo团队已经为Android准备了文档(在这里)。不过,文档有些信息不太明确,我也遇到了些困难,所以我想在这里写下我自己的备忘录,以备忘记。
基本上,我会根据这里的入门指南进行说明。
请在build.gradle文件中添加必要的插件。
首先,需要将必要的插件添加到build.gradle文件中。在项目目录的顶层build.gradle文件的dependencies块中添加以下classpath。
在查看Maven时,有apollo-gradle-plugin和gradle-plugin两个选项,但我们将使用apollo-gradle-plugin。
buildscript {
dependencies {
// 省略
+ classpath 'com.apollographql.apollo:apollo-gradle-plugin:0.5.0'
}
}
只需一种选项:在app目录下的build.gradle文件中添加以下两行。关于apply plugin: ‘com.apollographql.android’,需要在Android Plugin之后的位置写入,所以您可以将其添加到apply plugin的最底部即可。
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
+ apply plugin: 'com.apollographql.android'
// 省略
dependencies {
// 省略
+ implementation 'com.apollographql.apollo:apollo-runtime:0.5.0'
}
版本已全部更新为0.5.0。如果您查看以前的文章,会发现有些使用了0.4.1等版本,但可能会导致错误。总体而言,使用最新版本即可。
在完成对build.gradle的修改后,请同步并应用变更。
放置schema.json
您需要将定义了服务器GraphQL终点的架构文件放置在Android项目中。根据这个文件,Apollo将会检查开发者编写的GraphQL查询是否有效,并将其转换为Java文件
要获得schema.json,需要使用apollo-codegen命令。如果您尚未安装apollo-codegen命令,
yarn global add apollo-codegen
请安装yarn,如果您没有安装yarn可以通过brew install yarn进行安装。我们将检查apollo-codegen是否已正确安装并确认其版本。
$ apollo-codegen --version
0.20.2
接下来下载schema.json文件。
apollo-codegen download-schema https://hogehoge.com/graphql --output schema.json
schema.json在我的情况下,
被放置在app/src/main/graphql/com/hogehoge/schema.json,
但是需要放置在与.graphql文件相同的目录下。
创建一个.graphql文件
这次我们以以下的方式进行了实施。
query Category($id: ID!, $num: Int) {
category(id: $id) {
id
name
movies(num: $num) {
id
title
publishedAt
}
}
}
这里顺便提一下,关于movies部分的实现是通过ResponseField.forList这个方法实现的,但在v0.4.1中尚未实施,这种形式可能在那个时候并不起作用。从v0.4.2开始似乎有了这个选项。
在利用方实施中。
当准备使用okHttpClient和apolloClient时,可以按照(参考)中的指示进行操作。
apolloClient.query的参数应是之前创建的.graphql文件。如果尚未进行构建,则可能会出现错误,因为CategoryQuery类尚未生成。因此建议在添加.graphql文件时尝试进行构建。
在.graphql文件中定义的参数部分似乎会成为方法的一部分。
CategoryQuery.builder()
.id(2) // カテゴリーIDの奇数。$id
.num(6) // 動画の数の引数。$num
.build()
val okHttpClient = OkHttpClient.Builder().build()
val apolloClient = ApolloClient.builder()
.serverUrl("https://hogehoge.com/graphql") // サーバのホストのは、ローカルでサーバーを立てている場合、10.0.2.2になるらしいので注意。rails sで起動している場合は、http://10.0.2.2:3000となる。10.0.2.2でうまくいかない場合は、10.0.3.2なども試してみる。
.okHttpClient(okHttpClient)
.build()
// APIで取得したCategoryを格納するListを用意
// Categoryは簡単なdata classを別で定義。 => data class Category(val name: String)
val categories = mutableListOf<Category>()
// APIで取得後、adapterに更新を通知するため。APIコールは別スレッド。
val handler = Handler()
apolloClient.query(
CategoryQuery.builder().id("2").num(6).build()
).enqueue(
// ApolloCall.Callbackを実装した無名クラスを作成。必要なメソッドをoverrideする。
object : ApolloCall.Callback<CategoryQuery.Data>() {
override fun onResponse(response: Response<CategoryQuery.Data>) {
response.data()?.category()?.forEach {
categories.add(Category(it.name())) // サンプルのため、moviesは無視。
handler.post {
// adapterはRecyclerView用のadapter
adapter.categories = categories
adapter.notifyDataSetChanged()
}
}
}
override fun onFailure(e: ApolloException) {
Log.e("ApolloCall Failure", e.message, e)
}
}
)
我认为,如果使用RxAndroid等API,可能会更加简洁。
请参考
-
- Apollo GraphQL Client for Android
-
- APOLLO ANDROID GUIDE
-
- GitHub GraphQL API v4 を Android で遊んでみる
- Apollo-androidのレスポンスキャッシュを使ってみる
虽然据说可在apollo-cli上执行schema:download,但在使用Android Studio进行编译时,出现了”GraphQL schema file should contain a valid GraphQL introspection query result”的错误,无法成功进行。⏎
似乎也可以明确指定schema.json文件的路径。(参考)⏎