Criando meu pacote de erro usando Go
Tags: go, interface, errors, pkg
Published: 2024-01-02 19:35:20

---
title: Criando meu pacote de erro usando Go
published: true
description: Desvende os mistérios da manipulação de erros em Go ao criar seu próprio pacote personalizado, elevando suas habilidades de desenvolvimento com a poderosa combinação de interfaces e Go.
tags: go, interface, error, pkg
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-12-20 18:42 +0000
---

Neste artigo, vamos dar um rolê pela criação de erros usando Golang, ou seja, com sua biblioteca padrão. Depois desse aquecimento, vamos mergulhar no desenvolvimento do nosso próprio pacote.

Se você ainda não está familiarizado ou não manja muito de interfaces em Golang, eu super recomendo dar uma lida nesse [artigo](https://www.digitalocean.com/community/tutorials/how-to-use-interfaces-in-go-pt) antes, porque a coisa vai ficar intensa. Vamos explorar os pacotes padrão e desvendar como podemos usá-los para construir algo incrível. Então, prepara o café e vem comigo nessa jornada pelos segredos dos pacotes em Golang. Bora nessa?

---

Para começar, vamos explorar duas maneiras simples de criar erros em Golang, utilizando as bibliotecas padrão 'errors' e 'fmt'. Essas são ferramentas poderosas que vão nos permitir adicionar um toque personalizado aos nossos erros e deixar nossa aplicação mais robusta. Vamos lá!
1. Usando o pacote [errors](https://pkg.go.dev/errors)
```go
errors.New("failed operation") // Aqui vai retornar um novo erro com a mensagem `failed operation`
```
2. Usando o pacote [fmt](https://pkg.go.dev/fmt#Errorf)
```go
fmt.Errorf("failed again") // Aqui vai retornar um novo erro com a mensagem `failed again`
```
Uma característica fascinante do pacote fmt é a liberdade que ele oferece para personalizar os erros. Além disso, podemos dar um toque especial ao envolvê-los utilizando a referência %w. Vamos dar uma olhada prática nisso com um exemplo:
```go
errOp := fmt.Errorf("failed operation") // Cria um novo erro
errAgain := fmt.Errorf("%w: again", errOp) // Cria um novo erro que obtém como principal o `errOp`
```

Essa abordagem não apenas permite personalizar os erros, mas também oferece uma maneira inteligente de repassar informações sem a necessidade de fazer log em cada camada do código. Ao herdar o erro anterior e manter a mesma raiz, conseguimos construir um rastreamento completo do erro, proporcionando uma visão clara da jornada do problema. Uma técnica que não só simplifica, mas também enriquece o processo de identificação e resolução de falhas em nosso código.

---

> Agora, acredito que estamos prontos para dar o próximo passo e criar nosso próprio pacote, respeitando a interface error e aproveitando as funcionalidades do pacote padrão error. Bora lá!

---

Para iniciar essa jornada incrível, vamos criar uma estrutura personalizada. Vamos seguir a ideia de ter um erro com um código e uma mensagem, algo semelhante aos erros que encontramos no dia a dia das APIs REST. Essa abordagem não apenas facilita a identificação e tratamento de erros, mas também adiciona uma camada de clareza ao nosso código. Vamos colocar a mão na massa e ver o que conseguimos construir juntos!
```go
type myError struct {
	code int
	msg  string
}
```
Agora que temos nossa `struct` para representar erros personalizados na aplicação, o próximo passo é criar um método que não apenas instancie o erro, mas também retorne uma interface error. Dessa forma, nossa aplicação pode integrar suavemente esses erros personalizados ao fluxo padrão de manipulação de erros em Golang. Vamos criar esse método e garantir que nossos erros sejam facilmente utilizáveis!
```go
func NewError(code int, msg string) error {
	return &myError{
		code: code,
		msg:  msg,
	}
}
```
Vale destacar um ponto crucial que frequentemente é negligenciado e resulta em retrabalho desnecessário: muitas pessoas cometem o equívoco de retornar diretamente o ponteiro da estrutura na assinatura do método, em vez da interface error. Essa prática pode gerar complicações adicionais durante validações e manipulação de erros.

Para concluir nosso contrato, vamos adicionar um método `Error() string`. Esse método é essencial, pois atende ao contrato definido pela interface error, garantindo que nossos erros personalizados possam ser facilmente integrados e utilizados em qualquer contexto que espera uma implementação da interface error. Vamos fortalecer a base do nosso pacote, deixando-o ainda mais robusto e eficiente.
```go
func (e myError) Error() string {
	return fmt.Sprintf("%d: %s", e.code, e.msg)
}
```

Caramba, pessoal, não é que nosso pacote está pronto? E que tal irmos além e testarmos isso na prática? Vamos fazer um teste repassando nosso erro para frente, utilizando a técnica de wrap com outro erro, e em seguida, validar se o tipo do erro foi herdado corretamente. Ah, vai ser legal! Vamos lá, é hora de entrar nesse teste e garantir que nosso pacote está afiado. Go go go!
```go
// Criando um erro bad request
err := NewError(400, "bad request")

// Envelopando o erro not found dentro do bad request
errAgain := fmt.Errorf("%w: %v", err, NewError(404, "not found"))

// output:
// 400: bad request: 404: not found
fmt.Println(errAgain)

// Aqui estamos validando se o errAgain é herdado do bad request
// output
// true
fmt.Println(errors.Is(errAgain, err))
// Aqui a gente remove o errAgain e pega somente o original
// output
// 400: bad request
fmt.Println(errors.Unwrap(errAgain))
```

Em conclusão, a valorização e aplicação adequada das interfaces nativas do Go, com destaque para a interface error, revelam-se cruciais. Ao respeitar esses padrões, não apenas fortalecemos a consistência do código, mas também habilitamos rastreamentos mais eficientes quando necessários. Essa abordagem não apenas eleva a qualidade do código, mas também promove a reutilização, consolidando a robustez e flexibilidade no desenvolvimento em Go. Vamos adotar esses princípios para aprimorar continuamente nossa prática de programação em Go.

Para ver o código completo, [acesse aqui](https://gist.github.com/renanbastos93/f63538b4e75d0bd0fc2d56537206f186)!