O F# é uma linguagem funcional-first que roda no ecossistema .NET, com discriminated unions e composição de funções que tornam o tratamento de erros seguro e expressivo. Para integrar validação de CPF em F#, a API da CPFHub.io aceita GET https://api.cpfhub.io/cpf/{CPF} autenticado pelo header x-api-key e responde em ~900ms com nome, data de nascimento e status do documento. O Giraffe funciona como middleware sobre ASP.NET Core para exposição da rota; o Suave oferece uma alternativa funcional mais leve e independente. Consulte a documentação oficial do F# para configurar o .NET SDK antes de começar.
1. Pré-requisitos
-
.NET 8.0+ SDK instalado.
-
Um projeto F# criado:
dotnet new console -lang F# -n CpfValidatorFSharp. -
Uma conta gratuita na CPFHub.io
2. Adicione as dependências
dotnet add package Giraffe
dotnet add package FSharp.Data
dotnet add package Newtonsoft.Json
3. Defina os tipos de dados
Use discriminated unions para modelar resultados e erros:
// Types.fs
module CpfValidator.Types
open System.Text.Json.Serialization
type CpfData =
{ [<JsonPropertyName("cpf")>] Cpf: string
[<JsonPropertyName("name")>] Name: string
[<JsonPropertyName("nameUpper")>] NameUpper: string
[<JsonPropertyName("gender")>] Gender: string
[<JsonPropertyName("birthDate")>] BirthDate: string
[<JsonPropertyName("day")>] Day: int
[<JsonPropertyName("month")>] Month: int
[<JsonPropertyName("year")>] Year: int }
type CpfApiResponse =
{ [<JsonPropertyName("success")>] Success: bool
[<JsonPropertyName("data")>] Data: CpfData option }
type CpfError =
| InvalidCpf of string
| NotFound of string
| Unauthorized of string
| RateLimited of string
| TimeoutError of string
| ApiError of string * int
type CpfResult = Result<CpfData, CpfError>
4. Implemente o cliente da API
Crie o módulo de consulta usando HttpClient:
// CpfHubClient.fs
module CpfValidator.CpfHubClient
open System
open System.Net.Http
open System.Net.Http.Json
open System.Text.RegularExpressions
open System.Threading
open CpfValidator.Types
type CpfHubConfig =
{ ApiKey: string
BaseUrl: string
TimeoutMs: int }
let defaultConfig =
{ ApiKey = "SUA_CHAVE_DE_API"
BaseUrl = "https://api.cpfhub.io"
TimeoutMs = 5000 }
let private limparCpf (cpf: string) =
Regex.Replace(cpf, @"\D", "")
let private mapearErro (statusCode: int) =
match statusCode with
| 400 -> InvalidCpf "CPF com formato inválido"
| 401 -> Unauthorized "Chave de API inválida ou ausente"
| 404 -> NotFound "CPF não encontrado na base de dados"
// Nota: a CPFHub.io não retorna 429; ao exceder o plano gratuito,
// cobra R$0,15 por consulta adicional sem bloquear requisições.
| code -> ApiError ($"Erro HTTP {code}", code)
let consultarCpf (config: CpfHubConfig) (httpClient: HttpClient) (cpf: string) : Async<CpfResult> =
async {
let cpfLimpo = limparCpf cpf
if cpfLimpo.Length <> 11 then
return Error (InvalidCpf "CPF deve conter exatamente 11 dígitos")
else
let url = $"{config.BaseUrl}/cpf/{cpfLimpo}"
use cts = new CancellationTokenSource(config.TimeoutMs)
try
use request = new HttpRequestMessage(HttpMethod.Get, url)
request.Headers.Add("x-api-key", config.ApiKey)
request.Headers.Add("Accept", "application/json")
let! response =
httpClient.SendAsync(request, cts.Token)
|> Async.AwaitTask
if response.IsSuccessStatusCode then
let! resultado =
response.Content.ReadFromJsonAsync<CpfApiResponse>(cancellationToken = cts.Token)
|> Async.AwaitTask
match resultado with
| null -> return Error (ApiError ("Resposta nula da API", 500))
| r when r.Success ->
match r.Data with
| Some data -> return Ok data
| None -> return Error (ApiError ("Resposta sem dados", 500))
| _ -> return Error (ApiError ("Consulta sem sucesso", 500))
else
return Error (mapearErro (int response.StatusCode))
with
| :? OperationCanceledException ->
return Error (TimeoutError "Timeout ao consultar a API da CPFHub")
| :? HttpRequestException as ex ->
return Error (ApiError ($"Erro de conexão: {ex.Message}", 502))
| ex ->
return Error (ApiError ($"Erro inesperado: {ex.Message}", 500))
}
5. Crie o servidor com Giraffe
Implemente a API REST usando Giraffe sobre ASP.NET Core:
// Program.fs (versão Giraffe)
module CpfValidator.Program
open System
open System.Net.Http
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Giraffe
open CpfValidator.Types
open CpfValidator.CpfHubClient
let private errorToStatus (error: CpfError) =
match error with
| InvalidCpf _ -> 400
| NotFound _ -> 404
| Unauthorized _ -> 401
| RateLimited _ -> 429
| TimeoutError _ -> 504
| ApiError (_, code) -> code
let private errorToMessage (error: CpfError) =
match error with
| InvalidCpf msg -> msg
| NotFound msg -> msg
| Unauthorized msg -> msg
| RateLimited msg -> msg
| TimeoutError msg -> msg
| ApiError (msg, _) -> msg
let consultarCpfHandler (cpf: string) : HttpHandler =
fun next ctx ->
task {
let httpClient = ctx.GetService<IHttpClientFactory>().CreateClient()
let config = defaultConfig
let! resultado = consultarCpf config httpClient cpf |> Async.StartAsTask
match resultado with
| Ok data ->
return! json {| success = true; data = data |} next ctx
| Error error ->
ctx.SetStatusCode(errorToStatus error)
return! json {| success = false; error = errorToMessage error |} next ctx
}
let webApp : HttpHandler =
choose [
GET >=> routef "/api/cpf/%s" consultarCpfHandler
RequestErrors.NOT_FOUND "Recurso não encontrado"
]
let configureApp (app: IApplicationBuilder) =
app.UseGiraffe webApp
let configureServices (services: IServiceCollection) =
services.AddGiraffe() |> ignore
services.AddHttpClient() |> ignore
[<EntryPoint>]
let main args =
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(fun webHost ->
webHost
.Configure(configureApp)
.ConfigureServices(configureServices)
.UseUrls("http://0.0.0.0:5000")
|> ignore)
.Build()
.Run()
0
6. Versão com Suave
Alternativamente, use o Suave para um servidor mais leve e funcional:
// ProgramSuave.fs
module CpfValidator.ProgramSuave
open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
open Suave.RequestErrors
open System.Net.Http
open Newtonsoft.Json
open CpfValidator.Types
open CpfValidator.CpfHubClient
let private httpClient = new HttpClient()
let consultarCpfSuave (cpf: string) : WebPart =
fun ctx ->
async {
let config = defaultConfig
let! resultado = consultarCpf config httpClient cpf
let jsonResponse =
match resultado with
| Ok data ->
let body = JsonConvert.SerializeObject({| success = true; data = data |})
OK body
| Error error ->
let msg = errorToMessage error
let body = JsonConvert.SerializeObject({| success = false; error = msg |})
BAD_REQUEST body
return! jsonResponse ctx
}
let app : WebPart =
choose [
GET >=> pathScan "/api/cpf/%s" consultarCpfSuave
NOT_FOUND "Recurso não encontrado"
]
let main () =
startWebServer defaultConfig app
7. Teste a integração
dotnet run
curl -X GET http://localhost:5000/api/cpf/12345678900
Resposta esperada:
{
"success": true,
"data": {
"cpf": "12345678900",
"name": "João da Silva",
"nameUpper": "JOÃO DA SILVA",
"gender": "M",
"birthDate": "15/06/1990",
"day": 15,
"month": 6,
"year": 1990
}
}
8. Boas práticas
-
Discriminated Unions -- Use DUs para modelar todos os estados possíveis de uma operação, incluindo erros. O compilador garante tratamento exaustivo.
-
Result -- Use
Result<'T, 'E>para operações que podem falhar, evitando exceções no fluxo principal. -
Async workflows -- Use
async {}para operações assíncronas, mantendo o código funcional e composável. -
Timeout -- Configure timeout via
CancellationTokenSourcepara garantir que requisições não travem, respeitando a latência de ~900ms da API. -
HttpClientFactory -- No Giraffe, use
IHttpClientFactorypara gerenciar o ciclo de vida doHttpClient. -
LGPD -- A API da CPFHub.io é 100% compatível com a LGPD. Garanta conformidade no tratamento de dados pessoais em sua aplicação F#.
Perguntas frequentes
Como configurar autenticação ao consumir a API de CPF em F#?
A autenticação usa o header x-api-key em cada requisição. No HttpRequestMessage, adicione request.Headers.Add("x-api-key", config.ApiKey) antes de enviar. A chave de API é gerada no painel da CPFHub.io e deve ser lida de uma variável de ambiente ou secret manager — nunca embutida no código-fonte.
Qual a diferença entre usar Giraffe e Suave para expor a rota de consulta de CPF?
O Giraffe funciona como middleware sobre o ASP.NET Core, aproveitando toda a infraestrutura .NET (injeção de dependência, IHttpClientFactory, logging estruturado). O Suave é um servidor web autônomo, mais leve e sem dependências do ASP.NET, adequado para serviços simples ou ambientes com restrição de footprint. Para produção com múltiplos endpoints, Giraffe tende a ser mais fácil de operar.
O que acontece quando o limite de consultas mensais é atingido?
A CPFHub.io não bloqueia requisições ao atingir o limite do plano. O plano gratuito inclui 50 consultas mensais; acima disso, cada consulta adicional é cobrada a R$0,15 automaticamente. O plano Pro oferece 1.000 consultas por R$149/mês com o mesmo modelo de excedente proporcional.
Como o sistema de tipos do F# ajuda no tratamento de erros da integração?
O discriminated union CpfError força que todo ponto de uso trate explicitamente cada caso de falha — InvalidCpf, NotFound, Unauthorized, TimeoutError e ApiError. O compilador do F# gera aviso para pattern matching incompleto, eliminando a possibilidade de estados de erro não tratados chegarem ao cliente.
Conclusão
Integrar a API da CPFHub.io
Cadastre-se em cpfhub.io
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



