Introdução
Aplicativos modernos para iOS e macOS raramente dispensam a interação com servidores remotos. Seja para carregar dados de um feed de notícias, enviar um formulário de registro ou sincronizar arquivos — todas essas operações exigem uma implementação competente de um cliente HTTP. No ecossistema Swift, o desenvolvedor tem à sua disposição um poderoso framework nativo, o URLSession, que a cada ano se torna mais conveniente graças à adoção do async/await.
Neste artigo, vamos analisar como criar requisições HTTP corretamente em Swift, começando pelas estruturas básicas e chegando até técnicas avançadas de tratamento de erros e serialização de dados. Você aprenderá a escrever código de rede limpo, seguro e eficiente para seus aplicativos.
Fundamentos do URLSession: a primeira requisição HTTP
A classe URLSession é a base para qualquer trabalho de rede em Swift. Ela gerencia configuração, cache, sessões e a execução direta das requisições. Vamos analisar a requisição GET mais simples para obter dados de um servidor.
Criando uma requisição GET simples
import Foundation
// 1. Criamos a URLguard let url = URL(string: "https://api.example.com/users") else { print("URL inválida") return}
// 2. Criamos a requisição (por padrão é GET)var request = URLRequest(url: url)request.httpMethod = "GET"request.setValue("application/json", forHTTPHeaderField: "Accept")
// 3. Criamos a sessãolet session = URLSession.shared
// 4. Executamos a requisição (método antigo com closure)let task = session.dataTask(with: request) { data, response, error in if let error = error { print("Erro na requisição: \\(error.localizedDescription)") return } guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print("O servidor retornou um erro") return } if let data = data, let jsonString = String(data: data, encoding: .utf8) { print("Dados recebidos: \\(jsonString)") }}task.resume() // Importante! Iniciamos a tarefaPontos-chave: sempre verifique o status da resposta (200...299), não se esqueça de chamar resume() e trate os possíveis erros. Em projetos reais, esse código geralmente é isolado em uma camada de serviço separada.
Abordagem moderna: async/await
A partir do Swift 5.5, tornou-se possível usar async/await, o que torna o código muito mais legível e elimina a "pirâmide de closures".
func fetchUsers() async throws -> Data { guard let url = URL(string: "https://api.example.com/users") else { throw URLError(.badURL) } var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue("application/json", forHTTPHeaderField: "Accept") let (data, response) = try await URLSession.shared.data(for: request) guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { throw URLError(.badServerResponse) } return data}Este código pode ser chamado de qualquer função ou tarefa assíncrona, simplificando significativamente a lógica.
Trabalhando com JSON: Codable e modelos de dados
Raramente os dados chegam em formato "bruto". Na maioria das vezes, lidamos com JSON. O Swift oferece uma solução elegante: o protocolo Codable (que combina Encodable e Decodable).
Criando o modelo e fazendo a decodificação
// 1. Definimos a estrutura de dadosstruct User: Codable { let id: Int let name: String let email: String}
// 2. Função assíncrona para obter um array de usuáriosfunc fetchUsers() async throws -> [User] { let data = try await fetchUsersData() // do exemplo anterior let decoder = JSONDecoder() return try decoder.decode
```