Как настроить Apollo для работы с GraphQL в Android

—

от автора

Зачем статья

Недавно у меня появилась необходимость реализовать работу с бэком на GraphQL. Туториалов по настройке на Android, в отличие от REST не так много и большинство из них уже не совсем актуальны.

Что такое GraphQL

GraphQL — модная альтернатива REST API, которая позволяет запрашивать данные более оптимизированным способом, отдавая только нужные вам данные.

Настройка окружения

Делать запросы к серверу мы будем через Apollo — самая популярная библиотека для работы с GraphQL на данный момент.

Приступим к работе. Первым делом давайте добавим в манифест нужные разрешения для работы с сетью:

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

Далее необходимо подключить apollo. Идём в основной build.gradle и в разделе dependencies добавляем следующую строчку:

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

Теперь необходимо в файле build.gradle модуля app подключить дополнительные зависимости:

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. Осталось показать apollo файлы для генерирования моделей. Для этого делаем следующие шаги.

Переходим в папку app вашего проекта, далее src -> main. Здесь нам необходимо создать папку graphQL. Сюда мы будем складывать наши .graphql файлы.

Копируем в созданную папку файл, скачанный в предыдущем шаге — schema.json
Настройка окружения закончена, переходим к коду

Генерация кода моделей

Начнём с файлов .graphql. Тут будут храниться запросы.
В GraphQL есть два вида запросов:
query — аналог GET
mutation — аналог POST/PUT/DELETE

Предположим, что вы делаете сервис для заселения постояльцев в комнату в отеле для администраторов этого отеля. Приложение умеет делать 3 функции. Логинить пользователя(администратора), получать информацию о комнате по id и заселять постояльцев

Создадим файл loginUser.graphql в созданной в предыдущем разделе директории app/src/main/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:

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

Билдим проект и видим 3 сгенерированных модельки в папке app/build/generated/source/apollo/debug/service: GetRoomQuery, СheckUserInMutation, LoginUserMutation

Выполнение запросов

Создадим singleton класс NetworkService, который будет провайдить нам ApolloClient. В нём делаем 2 метода. 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     }   } } 

Теперь идём в наше activity или fragment, тут реализуем выполнение запросов. Для начала залогинемся:

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

Это пример работы с mutation. Данный запрос мы выполняли без токена в header. Теперь давайте рассмотрим пример работы с query, попробуем получить информации о комнате. Предположим, что комната нам отдается только с токеном. Выполняем запрос следующим образом:

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

В качестве домашнего задания попробуйте сами написать реализацию заселения постояльцев.

Полезные ссылки:

Документация apollo-client для Android
Github apollo-client android

ссылка на оригинал статьи https://habr.com/ru/post/501184/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *