# Como Consumir a API de CPF em Swift Usando URLSession

> Aprenda a consumir a API de consulta de CPF em Swift usando URLSession. Guia completo com async/await, tratamento de erros e boas práticas.

**Publicado:** 15/12/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/consumir-api-cpf-swift-urlsession

---


Para consumir a API de CPF da CPFHub.io em Swift, use `URLSession` com suporte nativo a `async/await` disponível desde o Swift 5.5. A integração envolve modelar a resposta com `Codable`, fazer uma requisição `GET` para `https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`, e decodificar o JSON retornado em structs tipadas. O resultado inclui nome, data de nascimento e gênero do titular em menos de um segundo.

## Introdução

Swift é a linguagem principal para desenvolvimento de aplicações Apple, e **URLSession** é a API nativa para realizar requisições HTTP. Ao consumir a API de CPF do CPFHub.io em Swift, você tem acesso a uma integração robusta e type-safe com suporte nativo a async/await desde o Swift 5.5.

## Modelando a resposta da API com Codable

O protocolo **Codable** do Swift permite decodificar JSON diretamente em structs tipadas, eliminando a necessidade de parsing manual.

```swift
import Foundation

struct CPFResponse: Codable {
 let success: Bool
 let data: CPFData
}

struct CPFData: Codable {
 let cpf: String
 let name: String
 let nameUpper: String
 let gender: String
 let birthDate: String
 let day: String
 let month: String
 let year: String
}

enum CPFError: Error, LocalizedError {
 case invalidCPF
 case networkError(Error)
 case invalidResponse
 case apiError(Int)
 case decodingError(Error)

 var errorDescription: String? {
 switch self {
 case .invalidCPF:
 return "CPF inválido. Verifique o formato."
 case .networkError(let error):
 return "Erro de rede: \(error.localizedDescription)"
 case .invalidResponse:
 return "Resposta inválida da API."
 case .apiError(let code):
 return "Erro da API: código \(code)"
 case .decodingError(let error):
 return "Erro ao decodificar: \(error.localizedDescription)"
 }
 }
}
```

| Tipo | Função | Benefício |
|------|--------|-----------|
| **CPFResponse** | Struct raiz da resposta | Decodificação automática do JSON |
| **CPFData** | Dados do CPF retornados | Acesso tipado a cada campo |
| **CPFError** | Enum de erros customizados | Mensagens claras para cada cenário de falha |

- **Codable** -- protocolo que combina Encodable e Decodable para serialização bidirecional
- **LocalizedError** -- protocolo que fornece mensagens de erro legíveis ao usuário
- **Enum com associated values** -- permite carregar dados adicionais em cada caso de erro

---

## Criando o serviço de consulta com async/await

Com Swift 5.5+, URLSession suporta async/await nativamente, tornando o código assíncrono muito mais legível.

```swift
import Foundation

class CPFService {
 private let baseURL = "https://api.cpfhub.io/cpf"
 private let apiKey: String
 private let session: URLSession

 init(apiKey: String, session: URLSession = .shared) {
 self.apiKey = apiKey
 self.session = session
 }

 func consultarCPF(_ cpf: String) async throws -> CPFData {
 let cpfLimpo = cpf.replacingOccurrences(
 of: "[^0-9]",
 with: "",
 options: .regularExpression
 )

 guard cpfLimpo.count == 11 else {
 throw CPFError.invalidCPF
 }

 guard let url = URL(string: "\(baseURL)/\(cpfLimpo)") else {
 throw CPFError.invalidCPF
 }

 var request = URLRequest(url: url)
 request.httpMethod = "GET"
 request.setValue(apiKey, forHTTPHeaderField: "x-api-key")
 request.timeoutInterval = 15

 do {
 let (data, response) = try await session.data(for: request)

 guard let httpResponse = response as? HTTPURLResponse else {
 throw CPFError.invalidResponse
 }

 guard (200...299).contains(httpResponse.statusCode) else {
 throw CPFError.apiError(httpResponse.statusCode)
 }

 let decoder = JSONDecoder()
 let cpfResponse = try decoder.decode(CPFResponse.self, from: data)

 guard cpfResponse.success else {
 throw CPFError.invalidResponse
 }

 return cpfResponse.data
 } catch let error as CPFError {
 throw error
 } catch let error as DecodingError {
 throw CPFError.decodingError(error)
 } catch {
 throw CPFError.networkError(error)
 }
 }
}
```

- **async throws** -- a função é assíncrona e pode lançar erros, obrigando o chamador a tratar ambos
- **session.data(for:)** -- versão async do URLSession que retorna uma tupla (Data, URLResponse)
- **guard let** -- padrão Swift para validação antecipada com saída rápida em caso de falha

---

## Validação local do CPF antes da chamada à API

Antes de consumir a API, é eficiente validar o CPF localmente usando o algoritmo dos dígitos verificadores.

```swift
extension String {
 var isCPFValid: Bool {
 let numbers = self.replacingOccurrences(
 of: "[^0-9]",
 with: "",
 options: .regularExpression
 )

 guard numbers.count == 11 else { return false }

 let digits = numbers.compactMap { Int(String($0)) }

 // Rejeitar sequências repetidas
 if Set(digits).count == 1 { return false }

 // Validar primeiro dígito verificador
 let sum1 = (0..<9).reduce(0) { $0 + digits[$1] * (10 - $1) }
 let remainder1 = sum1 % 11
 let check1 = remainder1 < 2 ? 0 : 11 - remainder1
 guard digits[9] == check1 else { return false }

 // Validar segundo dígito verificador
 let sum2 = (0..<10).reduce(0) { $0 + digits[$1] * (11 - $1) }
 let remainder2 = sum2 % 11
 let check2 = remainder2 < 2 ? 0 : 11 - remainder2
 guard digits[10] == check2 else { return false }

 return true
 }
}

// Uso combinado com o serviço
func validarEConsultar(cpf: String) async throws -> CPFData {
 guard cpf.isCPFValid else {
 throw CPFError.invalidCPF
 }

 let service = CPFService(apiKey: "sua-chave-aqui")
 return try await service.consultarCPF(cpf)
}
```

- **Extension** -- adiciona funcionalidade ao tipo String sem herança, padrão idiomático do Swift
- **compactMap** -- converte caracteres em inteiros descartando valores nil de forma segura
- **reduce** -- acumula a soma ponderada dos dígitos de forma funcional e concisa

A documentação oficial da Apple sobre [URLSession e concorrência estruturada](https://developer.apple.com/documentation/foundation/urlsession) é a referência para boas práticas com async/await em aplicações iOS.

---

## Tratamento avançado com retry e timeout

Em produção, é importante implementar lógica de retry para lidar com falhas transitórias de rede.

```swift
extension CPFService {
 func consultarComRetry(
 _ cpf: String,
 maxTentativas: Int = 3,
 delayBase: TimeInterval = 1.0
 ) async throws -> CPFData {
 var ultimoErro: Error?

 for tentativa in 0..<maxTentativas {
 do {
 return try await consultarCPF(cpf)
 } catch CPFError.invalidCPF {
 throw CPFError.invalidCPF
 } catch {
 ultimoErro = error
 if tentativa < maxTentativas - 1 {
 let delay = delayBase * pow(2.0, Double(tentativa))
 try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
 }
 }
 }

 throw ultimoErro ?? CPFError.invalidResponse
 }
}
```

| Tentativa | Delay | Tempo acumulado |
|-----------|-------|----------------|
| 1 | 0s | 0s |
| 2 | 1s | 1s |
| 3 | 2s | 3s |

- **Exponential backoff** -- o delay dobra a cada tentativa para não sobrecarregar a API
- **Task.sleep** -- suspende a task atual sem bloquear a thread
- **Erros não retentáveis** -- CPF inválido é lançado imediatamente, sem retry

---

## Perguntas frequentes

### Como configurar a API key do CPFHub.io de forma segura em um app Swift?

Armazene a API key no `Info.plist` do projeto como uma variável de ambiente, nunca no código-fonte. Acesse via `Bundle.main.object(forInfoDictionaryKey: "CPFHUB_API_KEY") as? String`. Para projetos com maior rigor de segurança, utilize o Keychain para armazenar e recuperar a chave após o primeiro acesso.

### A API retorna HTTP 429 quando o limite de consultas é atingido?

Não. A CPFHub.io nunca bloqueia requisições nem retorna HTTP 429. Quando o limite do plano é atingido, cada consulta adicional é cobrada a R$0,15. O plano gratuito inclui 50 consultas mensais sem cartão de crédito; o plano Pro oferece 1.000 consultas por R$149/mês. Seu código não precisa tratar o status 429.

### Como testar a integração com URLSession sem fazer chamadas reais à API?

Injete uma `URLSession` customizada no inicializador do `CPFService` usando o padrão de injeção de dependência já mostrado no guia. Em testes unitários, use `URLProtocol` para interceptar requisições e retornar respostas mockadas, evitando chamadas reais à API e consumo de cota durante o desenvolvimento.

### Qual é a latência esperada da API CPFHub.io em apps iOS?

A latência média da API é de ~900ms em condições normais de rede. Em apps iOS, configure `request.timeoutInterval = 15` para tolerar variações de conectividade mobile. A lógica de retry com exponential backoff cobre eventuais falhas transitórias sem impactar a experiência do usuário.

### Leia também

- [Como Integrar Validação de CPF em um App iOS com SwiftUI](https://cpfhub.io/blog/validacao-cpf-ios-swiftui)
- [Como consumir API de CPF em Flutter com Dart e pacote http](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-flutter-com-dart-e-pacote-http)
- [Como consumir API de CPF em React Native para apps mobile nativos](https://cpfhub.io/blog/como-consumir-api-cpf-react-native-apps-mobile-nativos)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)

---

## Conclusão

Consumir a API de CPF em Swift com URLSession é uma tarefa direta graças ao suporte nativo a async/await e ao protocolo Codable. Com a modelagem tipada da resposta, validação local do CPF, tratamento robusto de erros e lógica de retry, você tem uma integração pronta para produção em qualquer aplicação Apple. A combinação de segurança de tipos do Swift com a simplicidade da API da [**CPFHub.io**](https://www.cpfhub.io/) resulta em código limpo, testável e de fácil manutenção.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e publique sua primeira consulta de CPF em Swift em menos de 30 minutos.

