GraphQL API с Swift: пошаговый туториал на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в GraphQL и Swift

GraphQL — это язык запросов для API, который позволяет клиентам получать именно те данные, которые им нужны, и ничего лишнего. Для разработчиков iOS и macOS интеграция GraphQL открывает новые возможности для создания эффективных и гибких мобильных приложений. В этом туториале мы на практике разберем, как подключить GraphQL API к Swift-проекту, выполнить базовые запросы и мутации, а также обработать возможные ошибки.

В отличие от традиционного REST, GraphQL позволяет запрашивать несколько ресурсов за один запрос, что особенно важно для мобильных устройств с ограниченным трафиком. Мы будем использовать популярную библиотеку Apollo iOS — самое стабильное и документированное решение для работы с GraphQL на Swift.

Подготовка проекта и установка Apollo iOS

Шаг 1: Создание проекта и установка зависимостей

Откройте Xcode и создайте новый проект iOS (или macOS). Для работы с GraphQL мы установим Apollo iOS через Swift Package Manager (SPM).

  1. В Xcode выберите File → Add Packages
  2. Вставьте URL репозитория: https://github.com/apollographql/apollo-ios.git
  3. Выберите последнюю стабильную версию (на момент написания — 1.15+)
  4. Добавьте пакет в ваш таргет

Шаг 2: Генерация кода по схеме GraphQL

Apollo iOS использует кодогенерацию: вы описываете запросы в .graphql файлах, а утилита создает типизированный Swift-код. Для этого необходимо:

  1. Создайте папку GraphQL в проекте
  2. Поместите туда файл schema.graphqls (схему вашего API) — обычно ее можно получить через introspection
  3. Создайте файл запроса, например GetUser.graphql:
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    email
    posts {
      title
    }
  }
}

Затем добавьте Build Phase с запуском кодогенератора. Проще всего установить Apollo CLI через Homebrew:

brew install apollo-ios-cli

И выполнить команду в корне проекта:

./apollo-ios-cli generate

После этого в папке Sources/API появятся сгенерированные Swift-файлы с моделями данных.

Выполнение базовых GraphQL-запросов

Настройка клиента Apollo

Создайте экземпляр клиента Apollo, указав URL вашего GraphQL-эндпоинта. Обычно это делается в AppDelegate или в отдельном сервисном классе:

import Apollo

class NetworkService {
    static let shared = NetworkService()
    private(set) lazy var apollo: ApolloClient = {
        let url = URL(string: "https://your-api.com/graphql")!
        return ApolloClient(url: url)
    }()
}

Запрос данных (Query)

Теперь выполним запрос на получение пользователя. Сгенерированный код создаст структуру GetUserQuery:

import Foundation

class UserViewModel: ObservableObject {
    @Published var user: User?
    @Published var errorMessage: String?
    
    func fetchUser(id: String) {
        NetworkService.shared.apollo.fetch(query: GetUserQuery(id: id)) { [weak self] result in
            DispatchQueue.main.async {
                switch result {
                case .success(let graphQLResult):
                    if let userData = graphQLResult.data?.user {
                        self?.user = User(
                            id: userData.id,
                            name: userData.name,
                            email: userData.email
                        )
                    }
                case .failure(let error):
                    self?.errorMessage = "Ошибка: \(error.localizedDescription)"
                }
            }
        }
    }
}

Обратите внимание: мы используем @Published для реактивного обновления UI в SwiftUI. Для UIKit можно использовать делегаты или Combine.

Мутации и обработка ошибок

Выполнение мутации (Mutation)

Мутации в GraphQL используются для изменения данных (создание, обновление, удаление). Создадим файл CreatePost.graphql:

mutation CreatePost($title: String!, $content: String!) {
  createPost(input: { title: $title, content: $content }) {
    id
    title
    createdAt
  }
}

После генерации кода, вызов мутации выглядит так:

func createPost(title: String, content: String) {
    NetworkService.shared.apollo.perform(mutation: CreatePostMutation(title: title, content: content)) { result in
        switch result {
        case .success(let graphQLResult):
            if let post = graphQLResult.data?.createPost {
                print("Пост создан: \(post.title)")
            }
            if let errors = graphQLResult.errors {
                for error in errors {
                    print("GraphQL ошибка: \(error.message)")
                }
            }
        case .failure(let error):
            print("Сетевая ошибка: \(error)")
        }
    }
}

Обработка ошибок: сетевые и GraphQL-ошибки

Важно различать два типа ошибок:

  • Сетевые ошибки — проблемы с соединением, таймауты (обрабатываются в .failure)
  • GraphQL-ошибки — ошибки бизнес-логики сервера (содержатся в graphQLResult.errors)

Пример универсального обработчика:

func handleResult<T>(_ result: Result<GraphQLResult<T>, Error>, completion: (T?, String?) -> Void) {
    switch result {
    case .success(let graphQLResult):
        if let data = graphQLResult.data {
            completion(data, nil)
        } else if let error = graphQLResult.errors?.first {
            completion(nil, error.message)
        }
    case .failure(let error):
        completion(nil, "Сетевая ошибка: \(error.localizedDescription)")
    }
}

Оптимизация для реальных проектов

Кэширование и нормализация данных

Apollo iOS поддерживает кэширование по умолчанию. Вы можете настроить политику кэширования:

let store = ApolloStore()
let client = ApolloClient(url: url, store: store)

// Использовать кэш, затем запрос к серверу
let cachePolicy = CachePolicy.returnCacheDataAndFetch
apollo.fetch(query: query, cachePolicy: cachePolicy) { result in
    // ...
}

Подписки (Subscriptions) через WebSocket

Для real-time обновлений используйте WebSocket-транспорт. Установите дополнительный

Блоги

Рекомендаций по книгам