# Como Consumir a API de CPF em Kotlin Usando Ktor Client e Retrofit

> Aprenda a consumir a API de CPF em Kotlin usando Ktor Client e Retrofit. Comparação completa com exemplos práticos e boas práticas.

**Publicado:** 21/12/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/consumir-api-cpf-kotlin-ktor-retrofit

---


Para consumir a API de CPF da CPFHub.io em Kotlin, você pode usar Ktor Client — solução multiplataforma da JetBrains, ideal para projetos Kotlin Multiplatform — ou Retrofit, a biblioteca mais popular no ecossistema Android. Ambas se integram nativamente com coroutines e retornam o mesmo modelo de dados, tornando a troca entre elas simples quando necessário.

## Introdução

Kotlin oferece duas bibliotecas maduras para consumir APIs REST: **Ktor Client**, mantido pela JetBrains, e **Retrofit**, criado pela Square. Ambas são excelentes opções para integrar a API de CPF da CPFHub.io em aplicações Android ou backend Kotlin. A documentação oficial do Kotlin está disponível em [kotlinlang.org](https://kotlinlang.org/docs/home.html), onde você encontra referências completas sobre coroutines, serialização e clientes HTTP.

---

## Modelando a resposta da API

Independentemente da biblioteca HTTP escolhida, a modelagem dos dados é a mesma. Use **data classes** do Kotlin com anotações de serialização.

```kotlin
import kotlinx.serialization.Serializable

@Serializable
data class CPFResponse(
 val success: Boolean,
 val data: CPFData
)

@Serializable
data class CPFData(
 val cpf: String,
 val name: String,
 val nameUpper: String,
 val gender: String,
 val birthDate: String,
 val day: String,
 val month: String,
 val year: String
)

sealed class CPFResult {
 data class Success(val data: CPFData) : CPFResult()
 data class Error(val message: String, val code: Int? = null) : CPFResult()
}
```

| Classe | Uso | Biblioteca de serialização |
|--------|-----|---------------------------|
| **CPFResponse** | Resposta completa da API | kotlinx.serialization |
| **CPFData** | Dados do CPF | kotlinx.serialization |
| **CPFResult** | Sealed class para Result pattern | Nenhuma |

- **@Serializable** -- anotação do kotlinx.serialization para deserialização automática de JSON
- **Sealed class** -- padrão Kotlin para representar resultados com sucesso ou erro de forma type-safe
- **Data class** -- gera automaticamente equals, hashCode, toString e copy

---

## Implementação com Ktor Client

Ktor Client é a solução multiplataforma da JetBrains, ideal para projetos Kotlin Multiplatform (KMP).

```kotlin
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json

class CPFServiceKtor(private val apiKey: String) {
 private val client = HttpClient(CIO) {
 install(ContentNegotiation) {
 json(Json {
 ignoreUnknownKeys = true
 isLenient = true
 })
 }
 install(HttpTimeout) {
 requestTimeoutMillis = 15_000
 connectTimeoutMillis = 10_000
 }
 defaultRequest {
 header("x-api-key", apiKey)
 }
 }

 suspend fun consultarCPF(cpf: String): CPFResult {
 val cpfLimpo = cpf.replace(Regex("[^0-9]"), "")

 if (cpfLimpo.length != 11) {
 return CPFResult.Error("CPF deve conter 11 dígitos")
 }

 return try {
 val response: CPFResponse = client.get(
 "https://api.cpfhub.io/cpf/$cpfLimpo"
 ).body()

 if (response.success) {
 CPFResult.Success(response.data)
 } else {
 CPFResult.Error("CPF não encontrado")
 }
 } catch (e: ClientRequestException) {
 CPFResult.Error("Erro do cliente: ${e.response.status}", e.response.status.value)
 } catch (e: ServerResponseException) {
 CPFResult.Error("Erro do servidor: ${e.response.status}", e.response.status.value)
 } catch (e: Exception) {
 CPFResult.Error("Erro de conexão: ${e.message}")
 }
 }

 fun close() {
 client.close()
 }
}
```

- **HttpClient(CIO)** -- CIO é o engine coroutine-based do Ktor, ideal para alta concorrência
- **ContentNegotiation** -- plugin que configura serialização/deserialização automática de JSON
- **defaultRequest** -- aplica o header da API key em todas as requisições automaticamente

---

## Implementação com Retrofit

Retrofit é a biblioteca mais popular no ecossistema Android, baseada em interfaces anotadas.

```kotlin
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Path
import retrofit2.Response
import okhttp3.OkHttpClient
import okhttp3.Interceptor
import java.util.concurrent.TimeUnit

interface CPFApi {
 @GET("cpf/{cpf}")
 suspend fun consultarCPF(
 @Path("cpf") cpf: String
 ): Response<CPFResponseRetrofit>
}

data class CPFResponseRetrofit(
 val success: Boolean,
 val data: CPFDataRetrofit
)

data class CPFDataRetrofit(
 val cpf: String,
 val name: String,
 val nameUpper: String,
 val gender: String,
 val birthDate: String,
 val day: String,
 val month: String,
 val year: String
)

class CPFServiceRetrofit(private val apiKey: String) {
 private val authInterceptor = Interceptor { chain ->
 val request = chain.request().newBuilder()
 .addHeader("x-api-key", apiKey)
 .build()
 chain.proceed(request)
 }

 private val okHttpClient = OkHttpClient.Builder()
 .addInterceptor(authInterceptor)
 .connectTimeout(10, TimeUnit.SECONDS)
 .readTimeout(15, TimeUnit.SECONDS)
 .build()

 private val api: CPFApi = Retrofit.Builder()
 .baseUrl("https://api.cpfhub.io/")
 .client(okHttpClient)
 .addConverterFactory(GsonConverterFactory.create())
 .build()
 .create(CPFApi::class.java)

 suspend fun consultarCPF(cpf: String): CPFResult {
 val cpfLimpo = cpf.replace(Regex("[^0-9]"), "")

 if (cpfLimpo.length != 11) {
 return CPFResult.Error("CPF deve conter 11 dígitos")
 }

 return try {
 val response = api.consultarCPF(cpfLimpo)
 if (response.isSuccessful && response.body()?.success == true) {
 val body = response.body()!!.data
 CPFResult.Success(CPFData(
 cpf = body.cpf, name = body.name,
 nameUpper = body.nameUpper, gender = body.gender,
 birthDate = body.birthDate, day = body.day,
 month = body.month, year = body.year
 ))
 } else {
 CPFResult.Error("CPF não encontrado", response.code())
 }
 } catch (e: Exception) {
 CPFResult.Error("Erro de conexão: ${e.message}")
 }
 }
}
```

- **Interface anotada** -- Retrofit gera a implementação automaticamente a partir das anotações
- **Interceptor** -- middleware do OkHttp que adiciona o header de autenticação em todas as requisições
- **Response wrapper** -- permite verificar o status HTTP antes de acessar o body

---

## Comparação entre Ktor Client e Retrofit

A escolha entre as duas bibliotecas depende do contexto do seu projeto.

| Critério | Ktor Client | Retrofit |
|----------|-------------|----------|
| Multiplataforma (KMP) | Sim | Apenas JVM/Android |
| Configuração | Plugins modulares | Converters e interceptors |
| Serialização padrão | kotlinx.serialization | Gson ou Moshi |
| Curva de aprendizado | Moderada | Baixa (popular) |
| Coroutines nativo | Sim | Sim (desde v2.6) |
| Tamanho do bundle | Menor | Maior (OkHttp incluso) |

```kotlin
// Uso unificado com ambas as implementações
suspend fun main() {
 val apiKey = System.getenv("CPFHUB_API_KEY")
 ?: throw IllegalStateException("API key não configurada")

 // Com Ktor
 val servicoKtor = CPFServiceKtor(apiKey)
 when (val resultado = servicoKtor.consultarCPF("12345678909")) {
 is CPFResult.Success -> println("Ktor: ${resultado.data.name}")
 is CPFResult.Error -> println("Ktor erro: ${resultado.message}")
 }
 servicoKtor.close()

 // Com Retrofit
 val servicoRetrofit = CPFServiceRetrofit(apiKey)
 when (val resultado = servicoRetrofit.consultarCPF("12345678909")) {
 is CPFResult.Success -> println("Retrofit: ${resultado.data.name}")
 is CPFResult.Error -> println("Retrofit erro: ${resultado.message}")
 }
}
```

- **Ktor Client** -- escolha ideal se você precisa de suporte multiplataforma ou já usa Ktor no backend
- **Retrofit** -- escolha ideal para projetos Android tradicionais com equipe já familiarizada
- **Sealed class** -- ambas as implementações retornam o mesmo tipo, facilitando troca futura

---

## Perguntas frequentes

### Qual é a diferença prática entre Ktor Client e Retrofit para consumir a API de CPF?
Ktor Client é a escolha certa para projetos Kotlin Multiplatform (Android, iOS, backend compartilhado), pois funciona em todas as plataformas sem adaptações. Retrofit é mais adequado para projetos Android tradicionais com equipe já familiarizada com o ecossistema OkHttp. Ambas suportam coroutines nativamente e retornam os mesmos dados da API CPFHub.io.

### Como configurar timeout corretamente para a latência de ~900ms da API?
Configure `requestTimeoutMillis = 15_000` no Ktor ou `readTimeout(15, TimeUnit.SECONDS)` no OkHttp do Retrofit. A API CPFHub.io responde em cerca de 900ms em condições normais, mas timeouts de 15 segundos garantem margem para variações de rede sem deixar a UI travada.

### Como proteger a API key em projetos Android com Kotlin?
Nunca inclua a `x-api-key` diretamente no código-fonte. Use variáveis de ambiente para backend ou, em Android, armazene a chave no `local.properties` e acesse via `BuildConfig`. Para projetos em produção, considere um backend intermediário que faz a chamada à API CPFHub.io sem expor a chave no cliente.

### A API CPFHub.io retorna erro quando o limite de consultas é atingido?
Não. A CPFHub.io nunca bloqueia requisições nem retorna erro por limite de consultas. Quando o volume do plano é ultrapassado, a API continua respondendo normalmente e cobra R$0,15 por consulta adicional, debitado automaticamente. O plano gratuito oferece 50 consultas/mês sem cartão de crédito; o Pro inclui 1.000 consultas por R$149/mês.

### Leia também

- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)
- [KYC no Brasil: quais setores são obrigados a validar CPF por lei](https://cpfhub.io/blog/kyc-no-brasil-quais-setores-sao-obrigados-a-validar-cpf-por-lei)

---

## Conclusão

Tanto Ktor Client quanto Retrofit são opções maduras e confiáveis para consumir a API de CPF em Kotlin. A escolha depende do seu cenário: Ktor Client para projetos multiplataforma e modernos, Retrofit para projetos Android com ecossistema já estabelecido. Independentemente da escolha, a combinação de coroutines do Kotlin com a API da [**CPFHub.io**](https://www.cpfhub.io/) resulta em integrações limpas, assíncronas e prontas para produção.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e adicione validação de CPF ao seu app Kotlin em menos de 30 minutos.

