GraphQL API с Swift: пошаговый туториал
GraphQL становится стандартом для современных API благодаря гибкости и эффективности. В отличие от REST, где вы получаете фиксированную структуру данных, GraphQL позволяет запрашивать только то, что нужно. В этом туториале мы разберём, как интегрировать GraphQL API в приложения на Swift для iOS и macOS, используя библиотеку Apollo iOS. Вы научитесь выполнять запросы, мутации и обрабатывать ошибки.
1. Настройка проекта и установка Apollo iOS
Первый шаг — создать новый проект Xcode и добавить зависимость Apollo iOS через Swift Package Manager (SPM).
Шаг 1.1: Создание проекта
Откройте Xcode и создайте новый проект (iOS App или macOS App). Выберите SwiftUI или UIKit — наш пример будет работать с обеими платформами.
Шаг 1.2: Установка Apollo iOS через SPM
- В Xcode перейдите в
File → Add Packages... - Вставьте URL репозитория:
https://github.com/apollographql/apollo-ios.git - Выберите последнюю стабильную версию (например, 1.15.0) и нажмите Add Package.
- В появившемся окне выберите ваш проект и добавьте пакет Apollo.
Шаг 1.3: Генерация схемы и кода
Apollo iOS использует кодогенерацию на основе схемы GraphQL. Сначала скачайте схему вашего API (обычно через introspection query). Для теста мы будем использовать публичное API Countries GraphQL (https://countries.trevorblades.com).
Создайте файл schema.graphqls в корне проекта и поместите в него схему (её можно получить через GraphQL Playground). Затем добавьте скрипт генерации в Build Phases:
// Пример скрипта в Build Phases
if which apollo-ios-cli >/dev/null; then
apollo-ios-cli generate
else
echo "Apollo CLI не установлен. Установите через: brew install apollo-ios-cli"
fi
Установите CLI через Homebrew: brew install apollo-ios-cli.
2. Выполнение базового GraphQL-запроса
Теперь, когда проект настроен, напишем код для выполнения запроса. Мы будем получать список стран с их кодами и названиями.
Шаг 2.1: Создание GraphQL-запроса
В папке проекта создайте файл Countries.graphql и добавьте запрос:
query GetCountries {
countries {
code
name
}
}
После этого запустите кодогенерацию (через Build или терминал). Apollo создаст структуры GetCountriesQuery и GetCountriesQuery.Data.
Шаг 2.2: Настройка ApolloClient
Создайте менеджер сети:
import Apollo
class NetworkManager {
static let shared = NetworkManager()
private(set) lazy var apollo: ApolloClient = {
let url = URL(string: "https://countries.trevorblades.com")!
return ApolloClient(url: url)
}()
}
Шаг 2.3: Выполнение запроса в SwiftUI
Пример для SwiftUI:
import SwiftUI
struct ContentView: View {
@State private var countries: [GetCountriesQuery.Data.Country] = []
var body: some View {
List(countries, id: \.code) { country in
Text("\(country.name) (\(country.code))")
}
.onAppear {
loadCountries()
}
}
func loadCountries() {
NetworkManager.shared.apollo.fetch(query: GetCountriesQuery()) { result in
switch result {
case .success(let graphQLResult):
if let countries = graphQLResult.data?.countries {
self.countries = countries
}
case .failure(let error):
print("Ошибка запроса: \(error.localizedDescription)")
}
}
}
}
Запустите приложение. Если всё настроено верно, вы увидите список стран из API.
3. Работа с мутациями и аргументами
GraphQL не только читает данные, но и изменяет их через мутации. Рассмотрим пример с добавлением нового элемента (если API поддерживает). Для демонстрации будем использовать аргументы в запросе.
Шаг 3.1: Запрос с аргументами
Добавим в файл Countries.graphql новый запрос для получения страны по коду:
query GetCountry($code: ID!) {
country(code: $code) {
name
capital
currency
}
}
После генерации кода вы получите GetCountryQuery с параметром code.
Шаг 3.2: Выполнение запроса с аргументами
func loadCountry(code: String) {
NetworkManager.shared.apollo.fetch(query: GetCountryQuery(code: code)) { result in
switch result {
case .success(let graphQLResult):
if let country = graphQLResult.data?.country {
print("Страна: \(country.name), столица: \(country.capital ?? "нет")")
}
case .failure(let error):
print("Ошибка: \(error)")
}
}
}
Шаг 3.3: Мутация (пример с гипотетическим API)
Для мутации необходимо объявить её в .graphql файле:
mutation CreateCountry($input: CountryInput!) {
createCountry(input: $input) {
code
name
}
}
В Swift вызывайте мутацию аналогично запросу, но используя perform:
let input = CountryInput(code: "RU", name: "Россия")
NetworkManager.shared.apollo.perform(mutation: CreateCountryMutation(input: input)) { result in
// Обработка результата
}
4. Обработка ошибок и пагинация
Работа с реальным API требует обработки ошибок и работы с большими объёмами данных. Рассмотрим эти аспекты.
Шаг 4.1: Обработка ошибок GraphQL
GraphQL может возвращать частичные ошибки. Apollo предоставляет структуру GraphQLResult с полем errors:
func handleResult<T: GraphQLQuery>(result: Result<GraphQLResult<T.Data>, Error>) {
switch result {
case .success(let graphQLResult):