API на Swift: от теории к реальным запросам
Каждый iOS-разработчик рано или поздно сталкивается с необходимостью общения приложения с сервером. Будь то загрузка ленты новостей, отправка данных формы или стриминг в реальном времени — без API (Application Programming Interface) не обойтись. Но какой протокол выбрать? Классический REST, гибкий GraphQL или сверхскоростной gRPC?
В этой статье мы не просто перечислим плюсы и минусы. Мы разберем работу с API на Swift на реальных примерах, покажем код и дадим практические советы. Вы узнаете, как правильно структурировать сетевой слой, какие библиотеки использовать и когда каждый из подходов становится лучшим выбором.
Если вы пишете на Swift и хотите, чтобы ваше приложение общалось с бэкендом быстро, надежно и красиво — эта статья для вас. Поехали!
REST API на Swift: классика, которая не стареет
REST (Representational State Transfer) — это архитектурный стиль, который использует HTTP-методы (GET, POST, PUT, DELETE) для работы с ресурсами. Большинство публичных API (GitHub, Twitter, Stripe) построены именно на REST. Для Swift-разработчика это означает, что вы будете работать с JSON, URLSession или Alamofire.
Базовый GET-запрос с URLSession
Начнем с самого простого — получения данных. Представим, что нам нужно загрузить список пользователей с JSONPlaceholder:
import Foundation
struct User: Codable {
let id: Int
let name: String
let email: String
}
func fetchUsers() async throws -> [User] {
let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode([User].self, from: data)
}
Task {
do {
let users = try await fetchUsers()
print("Загружено \(users.count) пользователей")
} catch {
print("Ошибка: \(error.localizedDescription)")
}
}
Обратите внимание на использование async/await — это современный способ работы с асинхронным кодом в Swift. Код стал читаемым и коротким, без замыканий и callback-ов.
POST-запрос с Alamofire
Alamofire — это самая популярная библиотека для работы с сетью на Swift. Она упрощает обработку ошибок, кодирование параметров и загрузку файлов. Вот пример отправки данных:
import Alamofire
struct NewUser: Encodable {
let name: String
let email: String
}
AF.request("https://jsonplaceholder.typicode.com/users",
method: .post,
parameters: NewUser(name: "Иван", email: "ivan@example.com"),
encoder: JSONParameterEncoder.default)
.validate()
.responseDecodable(of: User.self) { response in
switch response.result {
case .success(let user):
print("Создан пользователь с id: \(user.id)")
case .failure(let error):
print("Ошибка: \(error.localizedDescription)")
}
}
Совет: Используйте .validate() — это автоматически проверит статус-код и преобразует ошибки HTTP в ошибки Alamofire. Ваш код станет чище, а отладка — проще.
Когда REST — лучший выбор?
- У вас простое CRUD-приложение (заметки, список задач).
- API предоставляет фиксированные эндпоинты.
- Вам не нужна сложная вложенность данных.
GraphQL на Swift: гибкость запросов
GraphQL — это язык запросов, который позволяет клиенту запрашивать ровно те данные, которые нужны. Никакого over-fetching (лишние поля) или under-fetching (нужно несколько запросов). Для Swift есть отличная библиотека Apollo iOS.
Настройка Apollo iOS
Сначала установите пакет через Swift Package Manager. Затем создайте файл схемы (например, schema.graphqls) или используйте кодогенерацию. Пример запроса:
import Apollo
let apollo = ApolloClient(url: URL(string: "https://countries.trevorblades.com")!)
let query = CountriesQuery() // Сгенерированная структура
apollo.fetch(query: query) { result in
switch result {
case .success(let graphQLResult):
if let countries = graphQLResult.data?.countries {
for country in countries {
print("\(country.name) - \(country.code)")
}
}
case .failure(let error):
print("Ошибка GraphQL: \(error)")
}
}
Ключевая фишка — вы сами решаете, какие поля вернуть. Например, можно запросить только название и код страны, без населения и столицы:
query Countries {
countries {
name
code
}
}
Это особенно полезно для мобильных приложений, где каждый килобайт трафика на счету.
Мутации (изменение данных)
GraphQL поддерживает не только чтение, но и запись через мутации:
let mutation = AddUserMutation(name: "Мария", email: "maria@example.com")
apollo.perform(mutation: mutation) { result in
// Обработка результата
}
Когда выбрать GraphQL?
- У вас сложные, вложенные данные (соцсети, e-commerce).
- Клиенты (iOS, Android, Web) требуют разные наборы полей.
- Вы хотите минимизировать количество запросов к серверу.
gRPC на Swift: скорость и типизация
gRPC (Google Remote Procedure Call) — это современный протокол, основанный на HTTP/2 и Protocol Buffers. Он обеспечивает высокую производительность, строгую типизацию и поддержку стриминга. Для Swift есть официальный плагин Swift gRPC.
Как это работает?
Вы описываете сервис и сообщения в .proto файле, затем генерируете Swift-код. Пример определения:
syntax = "proto3";
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
rpc ListUsers (Empty) returns (stream UserResponse); // Серверный стриминг
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
int32 id = 1;
string name = 2;
string email = 3;
}
После генерации вы получаете сгенерированные классы и протоколы. Клиентский код на Swift выглядит так:
import GRPC
import NIO
let group = PlatformSupport.makeEventLoopGroup(loopCount: 1)
let channel = try GRPCChannelPool.with(
target: .host("localhost", port: 50051),
transportSecurity: .plaintext,
eventLoopGroup: group
)
let client = UserServiceClient(channel: channel)
let request = UserRequest.with { $0.id = 123 }
let response = try client.getUser(request).response.wait()
print("Получен пользователь: \(response.name)")
Стриминг в реальном времени
Одно из главных преимуществ gRPC — поддержка стримов. Например, вы можете получать обновления курса валют или новые