Введение: почему GraphQL и Swift — идеальная пара
Современная iOS-разработка немыслима без эффективного взаимодействия с сервером. REST API постепенно уступает место более гибкой и производительной технологии — GraphQL. В этом туториале мы разберём, как интегрировать GraphQL API в Swift-приложение на практике, используя библиотеку Apollo iOS.
GraphQL позволяет запрашивать ровно те данные, которые нужны — ни больше, ни меньше. Для Swift это означает сокращение трафика, ускорение работы и упрощение кода. Мы пройдём полный путь: от настройки проекта до выполнения сложных запросов и мутаций.
1. Настройка проекта и установка Apollo iOS
Первый шаг — подготовка Xcode-проекта и установка зависимостей. Самый удобный способ — через Swift Package Manager.
1.1 Создание нового проекта
Откройте Xcode и создайте новый проект (iOS App или macOS App). Выберите SwiftUI или UIKit — не принципиально. Назовём его GraphQLDemo.
1.2 Добавление Apollo iOS через SPM
- В Xcode перейдите: File → Add Package Dependencies...
- Вставьте URL репозитория:
https://github.com/apollographql/apollo-ios.git - Выберите последнюю стабильную версию и нажмите Add Package.
- Убедитесь, что пакет добавлен в таргет вашего приложения.
1.3 Генерация кода схемы
Apollo iOS использует кодогенерацию. Для этого нам нужен файл схемы .graphqls (обычно скачивается с сервера) и файлы запросов .graphql.
// Структура проекта:
// GraphQLDemo/
// ├── GraphQL/
// │ ├── schema.graphqls // Схема сервера
// │ ├── Queries.graphql // Запросы
// │ └── Mutations.graphql // Мутации
После добавления файлов запустите кодогенерацию через терминал:
cd /путь/к/проекту
./Pods/Apollo/apollo-ios-cli --download-schema --endpoint=https://ваш-сервер/graphql
./Pods/Apollo/apollo-ios-cli --generate
Теперь у вас есть сгенерированные Swift-файлы с типами и запросами.
2. Базовый запрос (Query) на Swift
Разберём простейший запрос на получение списка пользователей. Предположим, наша схема содержит тип User с полями id, name, email.
2.1 Создание .graphql файла
В папке GraphQL создайте файл Queries.graphql:
query GetUsers {
users {
id
name
email
}
}
2.2 Выполнение запроса в Swift
Сначала инициализируем клиент Apollo:
import Apollo
class NetworkManager {
static let shared = NetworkManager()
let apollo: ApolloClient
private init() {
let url = URL(string: "https://ваш-сервер/graphql")!
apollo = ApolloClient(url: url)
}
}
Теперь выполним запрос в любом ViewController или ViewModel:
import SwiftUI
struct UsersView: View {
@State private var users: [GetUsersQuery.Data.User] = []
var body: some View {
List(users, id: \.id) { user in
VStack(alignment: .leading) {
Text(user.name)
.font(.headline)
Text(user.email)
.font(.subheadline)
.foregroundColor(.gray)
}
}
.onAppear {
loadUsers()
}
}
private func loadUsers() {
NetworkManager.shared.apollo.fetch(query: GetUsersQuery()) { result in
switch result {
case .success(let graphQLResult):
if let usersData = graphQLResult.data?.users {
self.users = usersData
}
case .failure(let error):
print("Ошибка: \(error.localizedDescription)")
}
}
}
}
Обратите внимание: типы GetUsersQuery и User сгенерированы автоматически. Никакого ручного парсинга JSON!
3. Мутации (Mutation) для изменения данных
Мутации в GraphQL используются для создания, обновления или удаления данных. Рассмотрим пример добавления нового пользователя.
3.1 Определение мутации
Файл Mutations.graphql:
mutation CreateUser($name: String!, $email: String!) {
createUser(name: $name, email: $email) {
id
name
email
}
}
3.2 Вызов мутации из Swift
struct AddUserView: View {
@State private var name = ""
@State private var email = ""
@State private var message = ""
var body: some View {
VStack(spacing: 20) {
TextField("Имя", text: $name)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Email", text: $email)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button("Создать пользователя") {
createUser()
}
Text(message)
.foregroundColor(.green)
}
.padding()
}
private func createUser() {
let mutation = CreateUserMutation(name: name, email: email)
NetworkManager.shared.apollo.perform(mutation: mutation) { result in
switch result {
case .success(let graphQLResult):
if let user = graphQLResult.data?.createUser {
self.message = "Пользователь \(user.name) создан!"
}
case .failure(let error):
self.message = "Ошибка: \(error.localizedDescription)"
}
}
}
}
Мутации выполняются методом perform (не fetch). Apollo автоматически обновляет кэш, если это необходимо.
4. Подписки (Subscription) для реального времени
Подписки — одна из сильнейших сторон GraphQL. Они позволяют получать обновления в реальном времени через WebSocket.
4.1 Настройка WebSocket транспорта
Apollo iOS поддерживает WebSocket. Для этого нужно добавить транспорт:
import ApolloWebSocket
extension NetworkManager {
func setupWebSocket() {
let webSocketTransport = WebSocketTransport(
request: URLRequest(url: URL(string: "wss://ваш-сервер/graphql")!)
)
let splitNetworkTransport = SplitNetworkTransport(
uploadingNetworkTransport: apollo.networkTransport,
webSocketNetworkTransport: webSocketTransport