如何配置Apollo以在Android中使用GraphQL

为什么是文章


最近,我需要在GraphQL中实现与后端一起使用。与REST不同,在Android上设置的教程并不多,而且大多数教程已不再相关。

什么是GraphQL


GraphQL是REST API的时髦替代品,它使您能够以更优化的方式查询数据,仅提供所需的数据。

环境设定


我们将通过Apollo向服务器发出请求,Apollo是目前使用GraphQL的最受欢迎的库。

让我们开始工作。首先,让我们在清单中添加使用网络所需的权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

接下来,您需要连接阿波罗。我们转到主要的build.gradle并在dependencies部分中添加以下行:

classpath 'com.apollographql.apollo:apollo-gradle-plugin:2.0.0'

现在,您需要在应用程序模块的build.gradle文件中添加其他依赖项:

implementation("com.apollographql.apollo:apollo-runtime:2.0.0")
implementation "com.apollographql.apollo:apollo-android-support:2.0.0"

另外,将插件连接添加到文件的最顶部:

apply plugin: 'com.apollographql.apollo'

同步项目后,我们需要配置模型的代码生成,使用该代码生成查询GraphQL。

让我们最小化开发环境并打开一个终端。转到包含项目的文件夹:

cd /Users/user/Desktop/ProjectName

如果您还没有npm,请先从官方网站上下载

安装apollo-codegen,该工具可让您下载schema.json,该文件将用作生成模型的apollo源:

npm install apollo-codegen

下载schema.json(您必须位于项目的目录中,其中出现了node_modules文件夹):

node_modules/.bin/apollo-codegen download-schema https://   api/ --output schema.json

现在在项目文件夹中,我们看到了schema.json文件。它仍然显示用于生成模型的阿波罗文件。为此,请执行以下步骤。

转到项目的应用程序文件夹,然后转到src-> main。在这里,我们需要创建一个graphQL文件夹。在这里,我们将添加.graphql文件。

将上一步下载的文件复制到创建的文件夹-schema.json中
设置环境,转到代码

模型代码生成


让我们从.graphql文件开始。请求将存储在这里。
GraphQL有两种类型的查询:
查询-GET
突变的类似物-POST / PUT / DELETE的类似物

假设您正在为该酒店的管理员提供将客人入住酒店房间的服务。该应用程序可以执行3个功能。登录用户(管理员),通过ID获取房间信息并填充来宾

。在上一节中创建的app / src / main / graphQL目录中创建一个loginUser.graphql文件。使用此文件,apollo将为用户名生成一个模型。

档案内容:

mutation loginUser($email:String!, $password:String!) {
    login(
        user: {
            email: $email,
            password: $password
        }
    ){
        email,
        token,
        refreshToken
    }
}

此外,我们需要getRoom.graphql文件,并在其帮助下生成一个模型来获取酒店房间:

query getRoom($room_id: String) {
    room(room_id: $room_id) {
        title,
        room_number,
        cheked_in_family_name,
        has_minibar
    }
}

最后的文件是checkUserIn.graphql签入。也使用突变:

mutation checkInFamily($room_id: String!, $family_name: String!) {
    room(
        room: {
            title: $family_name,
            room_id: $room_id
        }
    ){
        room_id,
        family_name,
        minibar_products{
            title,
            weight
        }
    }
}

我们构建项目,并在app / build / generate / source / apollo / debug / service文件夹中看到3个生成的模型:GetRoomQuery,CheckUserInMutation,LoginUserMutation

查询执行


创建一个单例NetworkService类,它将为我们提供ApolloClient。我们在其中做两种方法。getApolloClient()执行不需要令牌或任何其他参数的请求,以及getApolloClientWithTokenInterceptor(),我们将令牌放入请求中:

import com.apollographql.apollo.ApolloClient
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request

class NetworkService {

  fun getApolloClient(): ApolloClient {
    val okHttp = OkHttpClient
      .Builder()
      .build()

    return ApolloClient.builder()
      .serverUrl(BASE_URL)
      .okHttpClient(okHttp)
      .build()
  }

  fun getApolloClientWithTokenInterceptor(token: String): ApolloClient {

    val httpClient = OkHttpClient.Builder()
      .addInterceptor(Interceptor { chain: Interceptor.Chain ->
        val original: Request = chain.request()
        
        val builder: Request.Builder = original
          .newBuilder()
          .method(original.method, original.body)
        
        builder.header("Authorization", "Bearer $token")
        return@Interceptor chain.proceed(builder.build())
      })
      .build()

    return ApolloClient.builder()
      .serverUrl(BASE_URL)
      .okHttpClient(httpClient)
      .build()
  }

  companion object {
    private var mInstance: NetworkService? = null

    fun getInstance(): NetworkService? {
      if (mInstance == null) {
        mInstance = NetworkService()
      }
      return mInstance
    }
  }
}

现在我们转到活动或片段,在这里我们实现请求的执行。首先,请登录:

  private fun loginUser() {

    val client = NetworkService.getInstance()?.getApolloClient()
    val loginMutation = LoginUserMutation
      .builder()
      .email(emailEdit.text.toString())
      .password(passwordEdit.text.toString())
      .build()

    client
      ?.mutate(loginMutation)
      ?.enqueue(object : ApolloCall.Callback<LoginUserMutation.Data>() {

        override fun onResponse(response: Response<LoginUserMutation.Data>) {
          if (!response.hasErrors()) {
            val token = response.data?.login()?.token()
            val email = response.data?.login()?.email()
            // ,   ui,     
            runOnUiThread {
              //   ,  
            }
          }
        }

        override fun onFailure(e: ApolloException) {}
      })
  }

这是处理突变的一个例子。我们执行了此请求,但标头中没有令牌。现在,让我们看一个使用查询的示例,尝试获取有关会议室的信息。假设只给代币一个房间。我们执行请求如下:

  private fun getRoom() {
    val token = "123456"
    val client = NetworkService.getInstance()
      ?.getApolloClientWithTokenIntercetor(token)

    val roomId = "123"
    val allRoomsQuery = GetRoomQuery(Input.fromNullable(roomId))

    client
      ?.query(allRoomsQuery)
      ?.enqueue(object : ApolloCall.Callback<GetRoomQuery.Data>() {

        override fun onResponse(response: Response<GetRoomQuery.Data>) {
          if (!response.hasErrors()) {
            val familyName = response.data?.room()?.family_name()
          }
        }

        override fun onFailure(e: ApolloException) {}
      })
  }

作为一项家庭作业,请尝试为自己编写一个解决客人的实施方案。

有用的链接:

Android的
阿波罗客户端文档Github阿波罗客户端android

All Articles