Introdução: REST vs GraphQL — a velha batalha no novo mundo do Swift
Há muito tempo, na era do Objective-C e da despacho por seletores, a escolha entre REST e GraphQL não era tão crucial. REST era o rei, e JSON seu fiel escudeiro. Mas os tempos mudaram. Swift tornou-se uma linguagem com sistema de tipos forte, surgiram async/await, Codable e frameworks poderosos como Apollo iOS. Agora a pergunta "REST ou GraphQL?" soa diferente: "O que trará mais benefícios ao meu projeto Swift?"
Neste artigo, não vamos recontar a Wikipédia. Vamos pegar um exemplo real de aplicativo iOS para uma plataforma educacional (sim, a PythonLib) e ver como cada abordagem se comporta no código Swift. Você descobrirá quando REST ainda domina e quando GraphQL é o verdadeiro salvador.
Resumindo: como REST difere do GraphQL
Para quem está começando no assunto — conceitos básicos.
- REST é um estilo arquitetural onde cada recurso (usuário, curso, lição) tem sua própria URL. Você recebe uma estrutura de dados fixa que o servidor decidiu enviar. Muitas vezes — um monte de informações desnecessárias.
- GraphQL é uma linguagem de consulta. Você decide quais campos precisa. Um único ponto de entrada (
/graphql) e uma consulta pode substituir várias requisições REST.
No papel, GraphQL parece uma bala de prata. Mas em projetos Swift, há nuances que vamos analisar na prática.
Exemplo 1: Obtendo perfil do usuário e seus cursos
Abordagem REST em Swift (URLSession + Codable)
Suponha que temos uma API REST clássica. Para mostrar o perfil e a lista de cursos, são necessárias duas requisições:
// Modelosstruct UserProfile: Codable { let id: Int let name: String let email: String let avatarURL: String}
struct Course: Codable { let id: Int let title: String let progress: Double}
// Camada de redefunc fetchUserProfile(userId: Int) async throws -> UserProfile { let url = URL(string: "https://api.pythonlib.ru/users/\\(userId)")! let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode(UserProfile.self, from: data)}
func fetchCourses(userId: Int) async throws -> [Course] { let url = URL(string: "https://api.pythonlib.ru/users/\\(userId)/courses")! let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode([Course].self, from: data)}
// Usolet profile = try await fetchUserProfile(userId: 42)let courses = try await fetchCourses(userId: 42)Tudo simples e previsível. Mas há um problema: recebemos todos os campos do perfil, mesmo se precisarmos apenas do nome e email. Além disso — duas requisições de rede. Em conexões lentas, isso é doloroso.
Abordagem GraphQL em Swift (Apollo iOS)
Agora, a mesma coisa, mas via GraphQL. Primeiro, definimos a consulta em um arquivo .graphql:
query GetUserWithCourses($userId: ID!) { user(id: $userId) { id name email courses { id title progress } }}Apollo gera código Swift tipado automaticamente. No Xcode, fica assim:
import Apollo
let apolloClient = ApolloClient(url: URL(string: "https://api.pythonlib.ru/graphql")!)
func fetchUserWithCourses(userId: Int) async throws -> GetUserWithCoursesQuery.Data { return try await withCheckedThrowingContinuation { continuation in apolloClient.fetch(query: GetUserWithCoursesQuery(userId: userId)) { result in switch result { case .success(let graphQLResult): if let data = graphQLResult.data { continuation.resume(returning: data) } else if let errors = graphQLResult.errors {