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