Comment configurer Apollo pour fonctionner avec GraphQL dans Android

Pourquoi un article


Récemment, j'ai eu besoin d'implémenter le travail avec un backend dans GraphQL. Contrairement à REST, il n'y a pas tellement de tutoriels pour la configuration sur Android et la plupart d'entre eux ne sont plus tout à fait pertinents.

Qu'est-ce que GraphQL


GraphQL est une alternative à la mode à l'API REST, qui vous permet d'interroger les données de maniÚre plus optimisée, en ne donnant que les données dont vous avez besoin.

RĂ©glage de l'environnement


Nous ferons des requĂȘtes au serveur via Apollo - la bibliothĂšque la plus populaire pour travailler avec GraphQL en ce moment.

Mettons-nous au travail. Tout d'abord, ajoutons les autorisations nécessaires pour travailler avec le réseau au manifeste:

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

Ensuite, vous devez connecter apollo. Nous allons dans le build.gradle principal et dans la section des dépendances, ajoutons la ligne suivante:

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

Vous devez maintenant ajouter des dépendances supplémentaires dans le fichier build.gradle du module d'application:

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

De plus, ajoutez la connexion du plug-in tout en haut du fichier:

apply plugin: 'com.apollographql.apollo'

Une fois le projet synchronisĂ©, nous devons configurer la gĂ©nĂ©ration de code des modĂšles avec lesquels nous effectuerons des requĂȘtes sur GraphQL.

Minimisons l'environnement de développement et ouvrons un terminal. Accédez au dossier avec votre projet:

cd /Users/user/Desktop/ProjectName

Si vous n'avez pas encore npm, téléchargez d'abord sur le site officiel

Install apollo-codegen - un outil qui vous permet de télécharger schema.json - un fichier qui servira de source apollo pour générer des modÚles:

npm install apollo-codegen

TĂ©lĂ©chargez schema.json (vous devez ĂȘtre dans le rĂ©pertoire de votre projet, oĂč le dossier node_modules est apparu):

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

Maintenant, dans le dossier du projet, nous voyons le fichier schema.json. Il reste à montrer les fichiers apollo pour générer des modÚles. Pour ce faire, procédez comme suit.

Accédez au dossier d'application de votre projet, puis src -> main. Ici, nous devons créer un dossier graphQL. Ici, nous allons ajouter nos fichiers .graphql.

Copiez le fichier téléchargé à l'étape précédente dans le dossier créé - schema.json
L'environnement est configuré , allez dans le code

Génération de code de modÚle


Commençons par les fichiers .graphql. Les demandes seront stockées ici.
Il existe deux types de requĂȘtes dans GraphQL:
requĂȘte - analogique de la
mutation GET - analogique de POST / PUT / DELETE

Supposons que vous effectuez un service d'enregistrement de clients dans une chambre d'hĂŽtel pour les administrateurs de cet hĂŽtel. L'application peut effectuer 3 fonctions. Connectez-vous Ă  l'utilisateur (administrateur), obtenez des informations sur la chambre par id et

remplissez les invités Créez le fichier loginUser.graphql dans le répertoire app / src / main / graphQL créé dans la section précédente. L'utilisation de ce fichier apollo générera un modÚle pour le nom d'utilisateur.

Contenu du fichier:

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

De plus, nous avons besoin du fichier getRoom.graphql, avec son aide un modÚle est généré pour obtenir la chambre d'hÎtel:

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

Et le fichier final est l'enregistrement checkUserIn.graphql. Utilise Ă©galement la mutation:

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

Nous construisons le projet et voyons 3 modÚles générés dans le dossier app / build / généré / source / apollo / debug / service: GetRoomQuery, CheckUserInMutation, LoginUserMutation

ExĂ©cution de requĂȘte


Créez une classe NetworkService singleton qui nous fournira ApolloClient. Nous y faisons 2 méthodes. getApolloClient () pour exécuter les demandes qui ne nécessitent pas de jeton ou de paramÚtres supplémentaires, et getApolloClientWithTokenInterceptor (), dans lequel nous jetterons le jeton, pour les demandes:

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

Passons maintenant Ă  notre activitĂ© ou fragment, ici nous implĂ©mentons l'exĂ©cution des requĂȘtes. Pour commencer, connectez-vous:

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

Ceci est un exemple de travail avec mutation. Nous avons effectuĂ© cette demande sans jeton dans l'en-tĂȘte. Voyons maintenant un exemple de travail avec la requĂȘte, essayons d'obtenir des informations sur la salle. Supposons qu'une chambre ne nous soit donnĂ©e qu'avec un jeton. Nous exĂ©cutons la demande comme suit:

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

Comme devoir, essayez de vous Ă©crire une mise en Ɠuvre de l'installation des invitĂ©s.

Liens utiles:

documentation apollo-client pour Android
Github apollo-client android

All Articles