# Como Criar um CLI de Consulta de CPF em Go com Cobra

> Aprenda a criar uma ferramenta de linha de comando para consultar CPFs em Go usando Cobra, com subcomandos, flags, output formatado e autocomplete.

**Publicado:** 07/09/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/cli-consulta-cpf-go-cobra

---


Para criar um CLI de consulta de CPF em Go com Cobra, estruture o projeto com subcomandos separados para consulta via API, validação algorítmica local e processamento em lote — compilando para um binário estático distribuível em Linux, macOS e Windows. A biblioteca Cobra, a mesma usada no `kubectl` e no Docker CLI, oferece flags globais, autocomplete e output em múltiplos formatos com poucas linhas de configuração.

## Introdução

Ferramentas de linha de comando (CLI) são essenciais para automação, scripts e operações de suporte. Uma CLI de consulta de CPF permite que desenvolvedores e analistas consultem CPFs rapidamente sem precisar de interfaces gráficas ou chamadas manuais à API. O [Cobra](https://github.com/spf13/cobra) é a biblioteca mais utilizada para construir CLIs em Go, sendo a mesma usada no kubectl, Docker CLI e Hugo.

---

## Estrutura do projeto

A estrutura segue o padrão recomendado pelo Cobra para projetos CLI.

```go
// Estrutura de diretórios
// cpf-cli/
// cmd/
// root.go
// consultar.go
// lote.go
// validar.go
// internal/
// client/
// cpfhub.go
// formatter/
// output.go
// main.go
// go.mod
```

| Arquivo | Responsabilidade |
|---|---|
| `main.go` | Ponto de entrada |
| `cmd/root.go` | Comando raiz e flags globais |
| `cmd/consultar.go` | Subcomando para consulta individual |
| `cmd/lote.go` | Subcomando para consulta em lote |
| `cmd/validar.go` | Subcomando para validação algorítmica |
| `internal/client` | Cliente HTTP para a API |
| `internal/formatter` | Formatação de output |

---

## Comando raiz e configuração

O comando raiz define as flags globais e a estrutura base da CLI.

```go
// main.go
package main

import "cpf-cli/cmd"

func main() {
 cmd.Execute()
}

// cmd/root.go
package cmd

import (
 "fmt"
 "os"

 "github.com/spf13/cobra"
)

var (
 apiKey string
 outputFormat string
)

var rootCmd = &cobra.Command{
 Use: "cpf-cli",
 Short: "Ferramenta de linha de comando para consulta de CPF",
 Long: `cpf-cli permite consultar e validar CPFs via API do CPFHub.
Suporta consultas individuais, em lote e validação algoritmica local.`,
}

func Execute() {
 if err := rootCmd.Execute(); err != nil {
 fmt.Fprintln(os.Stderr, err)
 os.Exit(1)
 }
}

func init() {
 rootCmd.PersistentFlags().StringVar(
 &apiKey, "api-key", "",
 "Chave da API do CPFHub (ou CPFHUB_API_KEY)",
 )
 rootCmd.PersistentFlags().StringVarP(
 &outputFormat, "output", "o", "table",
 "Formato de saida: table, json, csv",
 )
}

func getAPIKey() string {
 if apiKey != "" {
 return apiKey
 }
 return os.Getenv("CPFHUB_API_KEY")
}
```

---

## Subcomando de consulta individual

O subcomando `consultar` faz a consulta de um CPF específico via API.

```go
// cmd/consultar.go
package cmd

import (
 "encoding/json"
 "fmt"
 "net/http"
 "os"
 "regexp"
 "text/tabwriter"
 "time"

 "github.com/spf13/cobra"
)

type APIResponse struct {
 Success bool `json:"success"`
 Data struct {
 CPF string `json:"cpf"`
 Name string `json:"name"`
 NameUpper string `json:"nameUpper"`
 Gender string `json:"gender"`
 BirthDate string `json:"birthDate"`
 Day int `json:"day"`
 Month int `json:"month"`
 Year int `json:"year"`
 } `json:"data"`
}

var consultarCmd = &cobra.Command{
 Use: "consultar [cpf]",
 Short: "Consulta um CPF via API do CPFHub",
 Args: cobra.ExactArgs(1),
 Example: " cpf-cli consultar 123.456.789-01\n cpf-cli consultar 12345678901 -o json",
 RunE: func(cmd *cobra.Command, args []string) error {
 key := getAPIKey()
 if key == "" {
 return fmt.Errorf("API key nao configurada. Use --api-key ou CPFHUB_API_KEY")
 }

 re := regexp.MustCompile(`\D`)
 cpf := re.ReplaceAllString(args[0], "")

 if len(cpf) != 11 {
 return fmt.Errorf("CPF deve conter 11 digitos, recebido: %d", len(cpf))
 }

 resultado, err := consultarAPI(cpf, key)
 if err != nil {
 return fmt.Errorf("erro ao consultar API: %w", err)
 }

 return exibirResultado(resultado)
 },
}

func consultarAPI(cpf, apiKey string) (*APIResponse, error) {
 url := fmt.Sprintf("https://api.cpfhub.io/cpf/%s", cpf)
 req, err := http.NewRequest("GET", url, nil)
 if err != nil {
 return nil, err
 }
 req.Header.Set("x-api-key", apiKey)

 client := &http.Client{Timeout: 10 * time.Second}
 resp, err := client.Do(req)
 if err != nil {
 return nil, err
 }
 defer resp.Body.Close()

 var resultado APIResponse
 if err := json.NewDecoder(resp.Body).Decode(&resultado); err != nil {
 return nil, err
 }
 return &resultado, nil
}

func exibirResultado(resultado *APIResponse) error {
 if !resultado.Success {
 fmt.Println("CPF nao encontrado na base de dados.")
 return nil
 }

 switch outputFormat {
 case "json":
 enc := json.NewEncoder(os.Stdout)
 enc.SetIndent("", " ")
 return enc.Encode(resultado.Data)
 case "csv":
 fmt.Printf("cpf,nome,genero,nascimento\n")
 fmt.Printf("%s,%s,%s,%s\n",
 resultado.Data.CPF,
 resultado.Data.Name,
 resultado.Data.Gender,
 resultado.Data.BirthDate,
 )
 default: // table
 w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
 fmt.Fprintln(w, "CAMPO\tVALOR")
 fmt.Fprintln(w, "-----\t-----")
 fmt.Fprintf(w, "CPF\t%s\n", resultado.Data.CPF)
 fmt.Fprintf(w, "Nome\t%s\n", resultado.Data.Name)
 fmt.Fprintf(w, "Genero\t%s\n", resultado.Data.Gender)
 fmt.Fprintf(w, "Nascimento\t%s\n", resultado.Data.BirthDate)
 w.Flush()
 }
 return nil
}

func init() {
 rootCmd.AddCommand(consultarCmd)
}
```

---

## Subcomando de validação local

O subcomando `validar` verifica o CPF algoritmicamente sem chamar a API.

```go
// cmd/validar.go
package cmd

import (
 "fmt"
 "regexp"
 "strconv"

 "github.com/spf13/cobra"
)

var validarCmd = &cobra.Command{
 Use: "validar [cpf]",
 Short: "Valida um CPF algoritmicamente (sem consultar API)",
 Args: cobra.ExactArgs(1),
 Example: " cpf-cli validar 123.456.789-01",
 Run: func(cmd *cobra.Command, args []string) {
 re := regexp.MustCompile(`\D`)
 cpf := re.ReplaceAllString(args[0], "")

 if len(cpf) != 11 {
 fmt.Printf("INVALIDO: CPF deve conter 11 digitos (recebido %d)\n", len(cpf))
 return
 }

 if validarDigitosCPF(cpf) {
 fmt.Printf("VALIDO: CPF %s possui digitos verificadores corretos\n", formatarCPF(cpf))
 } else {
 fmt.Printf("INVALIDO: CPF %s possui digitos verificadores incorretos\n", formatarCPF(cpf))
 }
 },
}

func validarDigitosCPF(cpf string) bool {
 todosIguais := true
 for i := 1; i < 11; i++ {
 if cpf[i] != cpf[0] {
 todosIguais = false
 break
 }
 }
 if todosIguais {
 return false
 }

 soma := 0
 for i := 0; i < 9; i++ {
 d, _ := strconv.Atoi(string(cpf[i]))
 soma += d * (10 - i)
 }
 resto := (soma * 10) % 11
 if resto == 10 {
 resto = 0
 }
 d9, _ := strconv.Atoi(string(cpf[9]))
 if resto != d9 {
 return false
 }

 soma = 0
 for i := 0; i < 10; i++ {
 d, _ := strconv.Atoi(string(cpf[i]))
 soma += d * (11 - i)
 }
 resto = (soma * 10) % 11
 if resto == 10 {
 resto = 0
 }
 d10, _ := strconv.Atoi(string(cpf[10]))
 return resto == d10
}

func formatarCPF(cpf string) string {
 return fmt.Sprintf("%s.%s.%s-%s", cpf[0:3], cpf[3:6], cpf[6:9], cpf[9:11])
}

func init() {
 rootCmd.AddCommand(validarCmd)
}
```

| Subcomando | Uso | Requer API Key |
|---|---|---|
| `consultar` | Consulta CPF via API | Sim |
| `validar` | Validação algorítmica local | Não |
| `lote` | Consulta múltiplos CPFs | Sim |

---

## Build e distribuição

Compile a CLI para múltiplas plataformas usando o sistema de build do Go.

```go
// Makefile
// build:
// GOOS=linux GOARCH=amd64 go build -o bin/cpf-cli-linux-amd64 .
// GOOS=darwin GOARCH=amd64 go build -o bin/cpf-cli-darwin-amd64 .
// GOOS=darwin GOARCH=arm64 go build -o bin/cpf-cli-darwin-arm64 .
// GOOS=windows GOARCH=amd64 go build -o bin/cpf-cli-windows-amd64.exe .
```

| Plataforma | Binário | Tamanho Aproximado |
|---|---|---|
| Linux AMD64 | cpf-cli-linux-amd64 | ~8MB |
| macOS AMD64 | cpf-cli-darwin-amd64 | ~8MB |
| macOS ARM64 | cpf-cli-darwin-arm64 | ~8MB |
| Windows AMD64 | cpf-cli-windows-amd64.exe | ~8MB |

---

## Perguntas frequentes

### Quais dependências externas são necessárias para construir o CLI?
O projeto depende de duas bibliotecas: `github.com/spf13/cobra` para a estrutura do CLI e a biblioteca padrão do Go para as chamadas HTTP. Não há dependências de terceiros para networking — o `net/http` nativo do Go é suficiente para consumir a API da CPFHub.io com timeout configurável.

### A CLI funciona sem conexão à internet?
O subcomando `validar` funciona completamente offline, pois executa apenas a validação algorítmica dos dígitos verificadores do CPF. Já o subcomando `consultar` requer conexão com a internet para acessar `https://api.cpfhub.io/cpf/{CPF}` e retornar nome, gênero e data de nascimento do titular.

### Como distribuir a CLI para uma equipe sem Go instalado?
O Go compila para binários estáticos sem dependências de runtime. Basta compilar para cada plataforma alvo (`GOOS/GOARCH`) e distribuir o executável diretamente — sem precisar instalar Go, Docker ou qualquer runtime adicional nas máquinas dos usuários.

### Como proteger a chave de API ao usar a CLI em scripts de CI/CD?
Prefira a variável de ambiente `CPFHUB_API_KEY` em vez da flag `--api-key` para evitar que a chave apareça nos logs do terminal. Em pipelines de CI, use secrets gerenciados pela plataforma (GitHub Actions Secrets, GitLab CI Variables etc.) e injete como variável de ambiente. Consulte as [boas práticas de segurança da OWASP](https://owasp.org/www-project-top-ten/) para proteção de credenciais em APIs.

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [SLA de API de CPF: níveis de disponibilidade e o que exigir do seu provedor](https://cpfhub.io/blog/sla-api-cpf-niveis-disponibilidade)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [10 erros mais comuns ao integrar uma API de CPF e como evitá-los](https://cpfhub.io/blog/10-erros-mais-comuns-ao-integrar-uma-api-de-cpf)

---

## Conclusão

Uma CLI de consulta de CPF construída com Go e Cobra é uma ferramenta poderosa para desenvolvedores, analistas e equipes de suporte. Com subcomandos claros, múltiplos formatos de saída e distribuição como binário estático, a ferramenta é portável e fácil de integrar em scripts de automação. A validação algorítmica local funciona sem API, enquanto a consulta via API retorna dados completos do titular.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a construir sua CLI de consulta de CPF com dados reais hoje mesmo.

