Cliente HTTP em Swift: fazendo requisições corretamente — nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: de GETs básicos ao cliente HTTP industrial

Uma requisição HTTP padrão em Swift são três linhas de código com URLSession.shared.dataTask. Mas em projetos reais (download de arquivos, autenticação com tokens, cache, retentativas) isso não é suficiente. Neste artigo, vamos explorar técnicas avançadas de criação de cliente HTTP em Swift para iOS e macOS: protocolos personalizados, gerenciamento de sessões, multithreading com async/await e Combine, além de tratamento robusto de erros. O material é voltado para desenvolvedores que já conhecem os fundamentos do URLSession.



Arquitetura de um cliente HTTP avançado

Um cliente industrial não é apenas uma função de requisição, mas uma camada de abstração. Vamos dividi-lo em três níveis:

  • Transport Layer — trabalho de baixo nível com URLSession, gerenciamento de configuração.
  • Service Layer — serialização/desserialização, tratamento de códigos de status, retentativas.
  • Application Layer — lógica de negócios, cache, autenticação.

Começaremos pela personalização da Transport Layer com URLProtocol.



1. URLProtocol personalizado para interceptar e modificar requisições

URLProtocol é um mecanismo poderoso para interceptar todas as requisições de rede no aplicativo. Com ele, é possível adicionar logging, assinatura de requisições ou dados mock para testes.

import Foundation

class LoggingProtocol: URLProtocol { override class func canInit(with request: URLRequest) -> Bool { // Intercepta todas as requisições HTTP/HTTPS return request.url?.scheme == "http" || request.url?.scheme == "https" }

override class func canonicalRequest(for request: URLRequest) -> URLRequest { return request }

override func startLoading() { print("📤 Requisição: \\(request.httpMethod ?? "GET") \\(request.url?.absoluteString ?? "")") print("📦 Cabeçalhos: \\(request.allHTTPHeaderFields ?? [:])")

let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in guard let self = self else { return } if let error = error { print("❌ Erro: \\(error.localizedDescription)") self.client?.urlProtocol(self, didFailWithError: error) } else if let data = data, let response = response { print("✅ Resposta: \\(response.expectedContentLength) bytes") self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed) self.client?.urlProtocol(self, didLoad: data) } self.client?.urlProtocolDidFinishLoading(self) } task.resume() }

override func stopLoading() { // Não faz nada, a tarefa é concluída sozinha }}

// Registro do protocoloURLProtocol.registerClass(LoggingProtocol.self)let config = URLSessionConfiguration.defaultconfig.protocolClasses = [LoggingProtocol.self]let session = URLSession(configuration: config)

Agora todas as requisições através desta sessão serão registradas. Da mesma forma, é possível adicionar a inserção automática do token Bearer ou o tratamento do status 401.



2. Gerenciamento de sessões: configuração personalizada e multithreading

Use diferentes URLSessionConfiguration para diferentes finalidades: .default para requisições comuns, .ephemeral para dados privados (sem cache e cookies), .background para downloads em segundo plano.

let backgroundConfig = URLSessionConfiguration.background(withIdentifier: "com.pythonlib.background")backgroundConfig.isDiscretionary = truebackgroundConfig.sessionSendsLaunchEvents = truelet backgroundSession = URLSession(configuration: backgroundConfig, delegate: self, delegateQueue: nil)

Para multithreading, use async/await (Swift 5.5+):

func performRequest(url: URL) async throws -> Data {    let (data, response)                

Blogs

Book Recommendations