Как проще всего выполнять запросы GraphQL в iOS



Книга Как проще всего выполнять запросы GraphQL в iOS

Такие сторонние библиотеки, как Apollo iOS client и AWS AppSync нужны для связи с сервером GraphQL в iOS-приложении, но они также вводят в ваш проект лишний код.


Клиент Apollo iOS нормализует результаты запросов для построения клиентского кэша с помощью базы данных SQLite. АWS AppSync снабжает клиент Apollo некоторыми дополнительными функциями для выполнения проверки подлинности AWS.


Я всегда чувствую себя неуверенно, когда связываю свой проект со сторонними библиотеками.


Поводы для беспокойства здесь следующие:


  • Насколько безопасна библиотека?
  • Что если библиотеку перестанут поддерживать?
  • Сколько времени уходит у команды поддержки на то, чтобы исправить ошибку и выпустить патч?
  • Кто же сообщает клиентам, что не может исправить ошибку по вине третьей стороны?

По счастью, есть простой и легкий способ выполнять GraphQL с помощью необработанного HTTP-запроса.


В этой статье продемонстрирую его пошаговую настройку (на основе Star War GraphQL API).


1.Операция query



В GraphQL есть три типа операций: query, mutation и subscription.


Запрос query извлекает данные из API. Это можно выполнить HTTP-методом GET или POST в зависимости от API GraphQL.


Для API Star War GraphQL применяется метод POST.


Далее приведен пример формы для стандартного POST-запроса GraphQL. Тип содержимого в этом запросе  —  application/json. А форма  —  это его тело, закодированное в JSON-формате.


{
"query": "...",
"variables": { "myVariable": "someValue", ... }
}

Начнем со строки query.


2.Строка query


В теле запроса это выглядит так:


let query: String =
"""
query allFilms($filter: FilmFilter) {
allFilms(filter: $filter) {
title
director
starships {
pilots {
name
}
}
}
}
"""

  • Здесь определяется строка запроса на получение фильмов с помощью фильтра.
  • Ключевое слово query в строке определяет тип операции, которая будет выполнена.
  • allFilms  —  это название операции. Оно не обязательно, но значимое и недвусмысленное имя помогает идентифицировать операцию.
  • $filter  —  это одна из переменных, принимаемых запросом, за которой следует тип фильтра Filter. Можно также передать другую переменную, а не создавать ее в запросе.
  • Блок fields описывает конкретные поля, которые мы запрашиваем, и имеет ту же форму, что и то, что мы получаем из API GraphQL.

{
title
director
starships {
pilots {
name
}
}
}

3.Кодируемые переменные


Как сказано в документации Star War GraphQL API, дополнения запроса allFilms таковы:


allFilms(
filter: FilmFilter
orderBy: FilmOrderBy
skip: Int
after: String
before: String
first: Int
last: Int
): [Film!]!

Они полностью опциональны. Продемонстрируем на примере Filter:


struct Filter: Encodable {
let director: String
}

struct Variable: Encodable {
let filter: Filter
}

let filter = Filter(director: "Irvin Kershner")
let variable = Variable(filter: filter)

У Filter, в свою очередь, тоже существует несколько опциональных свойств. Мы берем director только для упрощения демонстрационного кода.


Структуры Filter и Variable принимают протокол Encodable для подготовки тела в формате JSON.


4.Создание HTTP-запроса


struct Payload<T: Encodable>: Encodable {
let variables: T
let query: String
}

let payload = Payload(variables: variable, query: allFilmsQuery)
var request = URLRequest(url: swapiURL)
request.httpBody = try! JSONEncoder().encode(payload)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else {
return print("data is null")
}
let swiftyJsonVar = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
print(swiftyJsonVar)
}.resume()
struct Payload<T: Encodable>: Encodable {
let variables: T
let query: String
}

let payload = Payload(variables: variable, query: allFilmsQuery)
var request = URLRequest(url: swapiURL)
request.httpBody = try! JSONEncoder().encode(payload)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else {
return print("data is null")
}
let swiftyJsonVar = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
print(swiftyJsonVar)
}.resume()

Давайте разбираться:


  • Структура Payload содержит variables и query. Она также перенимает протокол Encodable.
  • request представляет собой экземпляр URLRequest, встроенный в Star War API URL: https://swapi.graph.cool.
  • payload кодируется в формате JSON и добавляется к телу запроса request.
  • Метод POST задействован согласно требованию Star War GraphQL API.
  • Для значений Content-Type and Accept в поле заголовка HTTP используется application/json.
  • request просто запускается одновременно с общим экземпляром URLSession.
  • Ответные данные находятся в формате JSON и могут быть десериализованы посредством JSONSerialization.

Заключение


В этой статье описывается наиболее облегчённый способ взаимодействия со службой GraphQL. Необработанный HTTP-запрос устраняет необходимость каких бы то ни было сторонних библиотек. Быстрый и чистый код целиком находится под контролем разработчика. 


Ресурсы


Все сторонние библиотеки, API GraphQL и образцы кода Swift можно найти по следующим ссылкам:



815   0  

Comments

    Ничего не найдено.