Executando verificação de segurança...
4

Validando e Gerando CPFs e CNPJs com Go: Apresentando o pacote cpfcnpj

No Brasil, CPF (Cadastro de Pessoa Física) e CNPJ (Cadastro Nacional da Pessoa Jurídica) são identificadores essenciais para pessoas e empresas. Em sistemas que lidam com cadastros de clientes, emissão de notas fiscais e integração com APIs governamentais, validar corretamente esses documentos é fundamental para evitar fraudes e garantir a qualidade dos dados.

Para facilitar esse processo em aplicações escritas em Go, apresento o cpfcnpj, um pacote leve e eficiente que permite:

  • Validar CPFs e CNPJs (numéricos e alfanuméricos).
  • Gerar CPFs e CNPJs válidos, com ou sem formatação.
  • Suportar o novo formato alfanumérico de CNPJ, que entrará em vigor em julho de 2026.

Instalação

Para instalar a versão mais recente, basta rodar:

go get github.com/jfelipearaujo/cpfcnpj@latest

Validação de CPF

Importe o pacote:

import "github.com/jfelipearaujo/cpfcnpj/cpf"

Crie uma instância do serviço:

svc := cpf.New()

Valide o CPF:

if err := svc.IsValid("123.456.789-09"); err != nil {
    fmt.Println("CPF inválido:", err)
} else {
    fmt.Println("CPF válido!")
}

O método IsValid retorna um erro quando o CPF não segue as regras de formação ou tem dígitos verificadores incorretos.

Validação de CNPJ

Importe o pacote:

import "github.com/jfelipearaujo/cpfcnpj/cnpj"

Crie uma instância do serviço:

svc := cnpj.New()

Valide um CNPJ (suporta alfanuméricos):

// Exemplo de CNPJ alfanumérico (válido a partir de julho/2026)
exemplo := "12.ABC.345/01DE-35"

if err := svc.IsValid(exemplo); err != nil {
    fmt.Println("CNPJ inválido:", err)
} else {
    fmt.Println("CNPJ válido!")
}

Geração de CPF

Para gerar CPFs válidos, use o método Generate:

svc := cpf.New()

// Gera um CPF numérico puro
novoCPF := svc.Generate()
fmt.Println("CPF gerado:", novoCPF)

// Gera um CPF com máscara (formato pretty)
novoCPFFormatado := svc.Generate(cpf.WithPrettyFormat())
fmt.Println("CPF formatado:", novoCPFFormatado)

Geração de CNPJ

A geração de CNPJs funciona de forma similar:

svc := cnpj.New()

// Gera um CNPJ numérico (versão V1, padrão)
novoCNPJ := svc.Generate()
fmt.Println("CNPJ gerado:", novoCNPJ)

// Gera um CNPJ com máscara
novoCNPJFormatado := svc.Generate(cnpj.WithPrettyFormat())
fmt.Println("CNPJ formatado:", novoCNPJFormatado)

Escolhendo a versão do CNPJ

Por padrão, o pacote gera CNPJs na Versão 1 (somente dígitos). Para experimentar a Versão 2 (alfanumérica), basta fazer o seguinte:

novoCNPJv2 := svc.Generate(cnpj.WithVersion(cnpj.V2))
fmt.Println("CNPJ alfanumérico (V2):", novoCNPJv2)

Este comportamento garante que sua aplicação já esteja preparada para o novo padrão que entrará em vigor em julho de 2026.

Conclusão

O cpfcnpj é uma solução robusta e flexível para lidar com validação e geração de CPFs e CNPJs em Go. Com suporte tanto ao formato numérico tradicional quanto ao futuro padrão alfanumérico, você garante que sua aplicação esteja pronta para exigências atuais e futuras, evitando retrabalho. A capacidade de gerar dados válidos automatizados facilita testes, demos e populações de ambiente de desenvolvimento com dados realistas. Experimente as funções de validação e geração apresentadas neste post e integre o pacote ao seu projeto para elevar a qualidade do tratamento de documentos fiscais. Contribua para o projeto, reporte issues e ajude a tornar o cpfcnpj ainda mais completo!

Carregando publicação patrocinada...
2

Uma coisa legal q aprendi recentemente é sobre problemas dos tipos primitivos e como melhorar eles. Talvez seja legal vc, além de ter esses validadores, tbm ter objetos complexos do tipo CPF e CNPJ. Assim dá uma alternativa melhor para quem utilizar seu package.

Esse é o vídeo do Renato Augusto explicando melhor sobre Object Calisthenics, mais especificamente nesse caso, sobre problemas dos tipos primitivos.
https://www.youtube.com/watch?v=YGNH71KPIes

Claro q só faça isso se vc quiser e se vc acredita no q é ensinado ali. Eu gostei bastante e parei de usar validadores desse jeito antigo, por isso eu acho interessante ter essas classes de CPF e CNPJ, já q são únicas e dificilmente irá mudar.

1

O problema dessa abordagem é que ela considera que os dados sempre virão por uma única fonte.

Quando os dados são lidos de um banco de dados que já existia antes da aplicação ou do uso dessa abordagem, você pode ter problemas em reconstruir objetos a partir desses dados.

Por exemplo, um new CPF('123.456.789-01') que lance uma exceção* em caso de dados inválidos é muito aceitável quando estamos falando de uma inclusão de um registro. Mas se ao recuperar esse dado do banco de dados e ele não for válido, sua aplicação vai ter que lidar com isso e ter if espalhado para todo lado.

Já vi problemas como esse surgirem com aplicações que herdaram bancos de dados legados, bancos de dados compartilhados com outras aplicações e com integrações.


Por conta disso, a abordagem que mais praticamos aqui é validar os dados na entrada antes da construção do objeto, com um zod da vida ou similar, e ter na classe CPF algo como isValid() : boolean para indicar se o valor contido ali é válido ou não.


*Sobre as exceções, é uma coisa que a gente também não usa aqui para validar dados. Nós encaramos exceções como exceções 🙃, o que é previsível a gente trata normalmente, por exemplo a entrada de dados de ambientes externos não serem válidas é algo totalmente previsível e facilmente checadas, então não lançamos exceção. No caso do TS/JS, uma das formas de aplicar isso é usando Either Monad.

Como em Go, a funções podem retornar diversos valores e err é uma coisa natural do uso da linguagem, não faz sentido usar Either Monad em Go. (e nem existe exceptions em Go).

Tenho visto muita gente usando exceções como controle de fluxo, principalmente a galera do PHP, quase como um goto.

1

Legal, é bom saber disso. Como estou fazendo do zero, então pelo menos não tenho problemas com isso. Eu atualmente aceito qqr valor dentro dele, ai a classe diz se o objeto é válido ou não pelos métodos dele. Não há tratamento de validade na criação do objeto.

Mas ficarei atento no q posso fazer nesses casos de inválidos, pois de qqr jeito se estiver errado, os dados precisarão ser corrigidos pelo input do usuário ou automaticamente (q é mais perigoso).

1
1

Ahahah, não posso, não conheço mto sobre go além do hello world, hahaha. É q ainda não deu tempo de aprender sobre o idioma pq tenho outras prioridades. Mas eu gostei do q fez e queria contribuir só com a sugestão msm, eheheh.

1
1

A forma de validação que foi feita no pacote consegue validar ambos os cenários sem nenhuma intervenção, seja o CNPJ com apenas números (versão 1) quanto o CNPJ que possui alfanuméricos (versão 2).

No pacote o único momento que se faz necessário especificar a versão é caso queira gerar um CNPJ, nesse caso o default é a versão 1, mas é possível informar que deseja usar a versão com alfanuméricos.

No arquivo de testes do CNPJ eu criei cenários para validar ambos os casos.

Veja um exemplo de teste para o CNPJ na versão com dígitos:

t.Run("Should return no error if CNPJ is valid", func(t *testing.T) {
    // Arrange
    input := "59.541.264/0001-03"

    sut := cnpj.New()

    // Act
    res := sut.IsValid(input)

    // Assert
    if res != nil {
        t.Errorf("Expected no error, got %v", res)
    }
})

Agora outro cenário com o CNPJ contendo alfanuméricos:

t.Run("Should return no error if CNPJ with letters is valid", func(t *testing.T) {
    // Arrange
    input := "12.ABC.345/01DE-35"

    sut := cnpj.New()

    // Act
    res := sut.IsValid(input)

    // Assert
    if res != nil {
        t.Errorf("Expected no error, got %v", res)
    }
})

Veja que a implementação e o uso do pacote é igual independente se recebeu um CPNJ na versão antiga ou na nova.

1

Sendo o CNPJ formado por 14 dígitos, e considerando que:

Os 8 primeiros: são o número base da empresa (identificação única).

Os 4 seguintes: Código da filial (matriz sempre têm 0001, filiais podem ter 0002, 0003, etc.).

Os dois últimos: Dígitos verificadores, usados para validar a autenticidade do CNPJ.

Acredito que as letras irão compor apenas o número base. E a fórmula para calcular o dígito verificador deve mudar.

Fonte: https://www.contabilizei.com.br/contabilidade-online/o-que-e-cnpj/

2