Como configurar o Apollo para funcionar com o GraphQL no Android

Por que um artigo


Recentemente, tive a necessidade de implementar o trabalho com um back-end no GraphQL. Não há muitos tutoriais para configuração no Android, ao contrário do REST, e a maioria deles não é mais relevante.

O que é o GraphQL


O GraphQL é uma alternativa elegante à API REST, que permite consultar dados de uma maneira mais otimizada, fornecendo apenas os dados necessários.

Configuração do ambiente


Faremos solicitações ao servidor por meio do Apollo - a biblioteca mais popular para trabalhar com o GraphQL no momento.

Vamos ao trabalho. Primeiro, vamos adicionar as permissões necessárias para trabalhar com a rede no manifesto:

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

Em seguida, você precisa conectar o Apollo. Vamos para o build.gradle principal e, na seção de dependências, adicionamos a seguinte linha:

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

Agora você precisa adicionar dependências adicionais no arquivo build.gradle do módulo de aplicativo:

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

Além disso, adicione a conexão do plug-in na parte superior do arquivo:

apply plugin: 'com.apollographql.apollo'

Após a sincronização do projeto, precisamos configurar a geração de código dos modelos com os quais faremos consultas ao GraphQL.

Vamos minimizar o ambiente de desenvolvimento e abrir um terminal. Vá para a pasta com seu projeto:

cd /Users/user/Desktop/ProjectName

Se você ainda não possui o npm, primeiro faça o download no site oficial

Instale o apollo-codegen - uma ferramenta que permite baixar o schema.json - um arquivo que servirá como fonte do apollo para gerar modelos:

npm install apollo-codegen

Faça o download do schema.json (você deve estar no diretório do seu projeto, onde a pasta node_modules apareceu):

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

Agora, na pasta do projeto, vemos o arquivo schema.json. Resta mostrar arquivos apollo para gerar modelos. Para fazer isso, execute as seguintes etapas.

Vá para a pasta do aplicativo do seu projeto e, em seguida, src -> main. Aqui precisamos criar uma pasta graphQL. Aqui vamos adicionar nossos arquivos .graphql.

Copie o arquivo baixado na etapa anterior para a pasta criada - schema.json
O ambiente está configurado , vá para o código

Geração de código do modelo


Vamos começar com os arquivos .graphql. Os pedidos serão armazenados aqui.
O GraphQL possui dois tipos de consultas:
consulta - um análogo da
mutação GET - um análogo de POST / PUT / DELETE

Suponha que você esteja prestando um serviço para fazer check-in de hóspedes em um quarto de um hotel para administradores deste hotel. O aplicativo pode fazer 3 funções. Faça login no usuário (administrador), obtenha informações da sala por ID e preencha convidados

Crie um arquivo loginUser.graphql no diretório app / src / main / graphQL criado na seção anterior. Usando este arquivo, o apollo irá gerar um modelo para o nome de usuário.

Conteúdo do arquivo:

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

Além disso, precisamos do arquivo getRoom.graphql, com a ajuda de um modelo para gerar o quarto de hotel:

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

E o arquivo final é checkUserIn.graphql. Também usa mutação:

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
        }
    }
}

Criamos o projeto e vemos 3 modelos gerados na pasta app / build / generate / source / apollo / debug / service: GetRoomQuery, CheckUserInMutation, LoginUserMutation

Execução de consulta


Crie uma classe NetworkService singleton que nos fornecerá o ApolloClient. Nós fazemos 2 métodos nele. getApolloClient () para executar solicitações que não exigem um token ou parâmetros adicionais e getApolloClientWithTokenInterceptor (), no qual lançaremos o token, para solicitações:

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
    }
  }
}

Agora vamos para nossa atividade ou fragmento, aqui implementamos a execução de solicitações. Para começar, faça o login:

  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) {}
      })
  }

Este é um exemplo de trabalho com mutação. Executamos essa solicitação sem um token no cabeçalho. Agora, vejamos um exemplo de trabalho com consulta, tente obter informações sobre a sala. Suponha que uma sala nos seja dada apenas com um token. Executamos a solicitação da seguinte maneira:

  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) {}
      })
  }

Como lição de casa, tente escrever uma implementação para acomodar convidados.

Links úteis:

documentação do apollo-client para Android
Github apollo-client android

All Articles