Bazel é um ferramenta criada e mantida pela Google que ajuda no processo de build de várias linguagens, sendo uma delas nosso querido Golang.
Duas de suas grandes vantagens são:
- Build de multiplas aplicações em monorepo sem precisar ficar entrando e saindo de pastas.
- Cache remoto das etapas de build (para mais detalhes, leia o post “Como Bazel funciona internamente“).
Embora para maioria das linguagens toda criação e manutenção dos arquivos do Bazel tenha que ser feita manualmente, para o Go temos o gazelle, uma ferramenta que nos auxilia nesse processo.
Se você ainda não tem o Bazel instalado na sua máquina, siga o tutorial do próprio site oficial segundo o OS que você utiliza. Se você já tem, execute um bazel version para garantir que você está utilizando a última versão (4.2.2).
Como aplicação exemplo, vamos utilizar o mesmo código do post Implementando uma API com gorilla/mux, mas separando as duas funções de “handler” em um novo package chamado handlers.
O estrutura de pastas/arquivos deve ser a seguinte:
- handlers
- hello.go
- person.go
- go.mod
- go.sum
- main.go
Para que você não precise olhar no outro post, segue como devem ficar os arquivos:
handlers/hello.go
package handlers
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func HandleHello(w http.ResponseWriter, rq *http.Request) {
vars := mux.Vars(rq)
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"message": fmt.Sprintf("Hello %s", vars["name"]),
})
}
handlers/person.go
package handlers
import (
"encoding/json"
"fmt"
"net/http"
)
type Person struct {
Name string `json:"name"`
Age uint8 `json:"age"`
}
func HandlePerson(w http.ResponseWriter, rq *http.Request) {
var p Person
err := json.NewDecoder(rq.Body).Decode(&p)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Fprintf(w, "Nome: %s - Idade: %d\n", p.Name, p.Age)
}
main.go
package main
import (
"net/http"
"github.com/aprendagolang/gorilla/handlers"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/{name}", handlers.HandleHello).Methods("GET")
r.HandleFunc("/person", handlers.HandlePerson).Methods("POST")
http.ListenAndServe(":8080", r)
}
Agora é só executar go mod init github.com/aprendagolang/gorilla para gerar o arquivo go.mod, e go mod tidy para gerar o go.sum.
Com a API pronta, vamos começar criar os arquivos de configuração do Bazel.
Quando usamos o gazelle para nos auxiliar, basicamente precisamos criar dois arquivos no root do nosso projeto. Esses arquivos são o WORKSPACE, que é responsável por toda gestão das dependências do Bazel, e o arquivo BUILD, que é onde vamos definir algumas regras.
Com a criação desses dois arquivos, nossa estrutura de pastas e arquivos deve ser a seguinte agora.
- handlers
- hello.go
- person.go
- BUILD
- go.mod
- go.sum
- main.go
- WORKSPACE
No arquivo WORKSPACE, antes de qualquer coisa, precisamos importar/fazer load da função do Bazel chamada http_archive. Essa função será utilizada para fazer download das regras do Go e do gazelle.
Após o download dessas regras, vamos fazer o load das funções go_register_toolchains e go_rules_dependencies, que estão presentes nas regras do Go, e as funções gazelle_dependencies e go_repository que estão presentes nas regras do gazelle.
Por último, vamos chamar as funções go_rules_dependencies(), go_register_toolchains(version = "1.17.2") e gazelle_dependencies().
Com todas essas etapas descritas, o arquivo WORKSPACE deve ficar assim:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
sha256 = "2b1641428dff9018f9e85c0384f03ec6c10660d935b750e3fa1492a281a53b0f",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.29.0/rules_go-v0.29.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.29.0/rules_go-v0.29.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
sha256 = "de69a09dc70417580aabf20a28619bb3ef60d038470c7cf8442fafcf627c21cb",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
go_rules_dependencies()
go_register_toolchains(version = "1.17.2")
gazelle_dependencies()
Com as dependências definidas e configuradas no WORKSPACE, vamos para o arquivo BUILD.
Nesse arquivo fazer o load da função gazelle, definir o gazelle:prefix com o nome do nosso módulo e chamar a função que carregamos no inicio.
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix github.com/aprendagolang/gorilla
gazelle(name = "gazelle")
Agora vamos executar o comando bazel run gazelle e ver a mágica acontecer.
Se você olhar na pasta handlers, vai ver que um arquivo BUILD.bazel foi criado com uma função go_library toda configurada, com os arquivos do package e suas dependências.
Já no arquivo BUILD que havíamos criado no inicio, o gazelle adicionou uma função go_library para configurar nosso main.go e suas dependências, e uma função go_binary, onde aponta para a go_library que contém o ponto de entrada do nosso programa, ou seja, a função main.
Antes de executar nossa API, vamos executar um comando do Bazel para gerar/atualizar um arquivo deps.bzl com todas as dependências externas do nosso projeto.
bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%go_dependencies
Se você olhar o arquivo WORKSPACE, verá que foram adicionadas as linhas:
load("//:deps.bzl", "go_dependencies")
# gazelle:repository_macro deps.bzl%go_dependencies
go_dependencies()
Agora que temos tudo configurado, podemos iniciar nossa API com o comando bazel run gorilla. A primeira execução pode ser um pouco mais lenta, pois ele está gerando o cache das etapas de build. Mas se você parar a API e executar o comando novamente, verá que o build é praticamente instantâneo.
Na próxima parte, vamos adicionar as regras do Bazel para gerar uma imagem docker e subir para um registry. Então se inscreva em nossa newsletter para não ficar de fora!
Deixem suas dúvidas nos comentários.
Até a próxima!
Faça parte da comunidade!
Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.
Livros Recomendados
Abaixo listei alguns dos melhores livros que já li sobre GO.

