使用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
image.png
image.png

我快速地准备了服务器端的工作。虽然这次我使用了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
    }
  }
}
image.png

这里顺便提一下,关于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文件的路径。(参考)⏎

广告
将在 10 秒后关闭
bannerAds