Hi, I'm João Vanzuita, a Backend software developer.

Gerando Especificação OpenAPI com Go Lang e Swagger

OpenAPI é uma padrão de especificação de API, criado de maneira a facilitar o processo de desenvolvimento e o entendimento do que a API realiza, de uma maneira simples em que programadores e utilizadores da API possam ler, utilizar e experimentar o seu funcionamento de forma simples e rápida.

O HTTP Swagger é um wrapper para automatizar a geração de especificação de API utilizando Swagger versão 2.0.

Os PROs gerando a documentação da API dessa forma são:

  • approach documentação como código.

  • a documentação fica próxima da função que a utiliza, qualquer dúvida ou atualização, o que precisa ser consultado e atualizado estão próximos.

  • Em Go Lang, se algo está errado, o código não compila. Em outras palavras, se a definição da API estiver errada, eu logo noto e posso rapidamente corrigi-la.

Mão na massa!

1. O primeiro passo é iniciar o projeto:

1mkdir seu-projecto
2cd $_
3go mod init github.com/<seu-user>/seu-projeto

2. Inicie a API básica

Nesse exemplo crio duas funções, um endpoint GET e outro POST.

2.1 Endpoint básico para mostrar a versão da sua API

Utilizo o router Chi, porque preciso definir os verbos GET e POST no router, e não somente verificar o verbo na função. Por exemplo, tenho um endpoint fictício [GET] `/teste`, neste endpoint definimos a especificacão OpenAPI para este endpoint, quando quero um verbo [POST] para a mesma entidade, eu preciso de um router p/ definir qual função é responsável pelo [GET] e qual função é responsável pelo [POST], vou mostrar isso, na prática, um pouco mais a frente.

1func main() {
2	r := chi.NewRouter()
3	r.Get("/", version)
4	fmt.Println("API listening at port 3001...")
5	err := http.ListenAndServe(":3001", r)
6	if err != nil {
7		log.Fatal(err)
8	}
9}

P/ informar a minha API que uma especificação OpenAPI será criada, preciso criamos um endpoint chamado `/swagger`, e definimos a espcificacão inicial. Neste endpoint `/swagger` a documentação auto gerada estará disponível usando a UI do Swagger. P/ isso defino este endpoint na API da seguinte forma:

1r.Get("/swagger/*", httpSwagger.WrapHandler)

E adiciono a especificação OpenAPI p/ a função main, que ficará:

1// @title Titulo da sua API
2// @version 1.0
3// @description Descricão longa da sua API
4// @termsOfService http://swagger.io/terms/
5// @license.name Apache 2.0
6// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
7// @host localhost:3001
8// @BasePath /
9func main() {
10    r := chi.NewRouter()
11    r.Get("/", version)
12    r.Get("/swagger/*", httpSwagger.WrapHandler)
13    fmt.Println("API listening at port 3001...")
14    err := http.ListenAndServe(":3001", r)
15    if err != nil {
16        log.Fatal(err)
17    }
18}

Agora defino o exemplo p/ o endpoint `[GET] /` sem a especificação OpenAPI:

1
2func version(w http.ResponseWriter, r *http.Request) {
3	w.Write([]byte("version: 1.0.0"))
4}

E em seguida defino a especificacão OpenAPI da seguinte forma p/ este endpoint:

1// version godoc
2// @Summary Get API version
3// @Description Get API version
4// @Tags version
5// @Accept  json
6// @Produce  json
7// @Success 200 {object} string
8// @Router / [get]

2.2 Adicionando os imports necessários

O primeiro import é importante p/ informar onde a minha definição da API está localizada, em seguida importo o router e o http-swagger que é responsável em ler os comentários e transformar em especificação no formato OpenAPI.

Primeiro instalo a biblioteca Chi:

1go get -u github.com/go-chi/chi/v5
2go get -u github.com/swaggo/swag/cmd/swag
3go get -u github.com/swaggo/http-swagger

E adiciono os importes:

1_ "github.com/converge/strave-stories/docs" // docs is generated by Swag CLI, you have to import it.
2"github.com/go-chi/chi/v5"
3httpSwagger "github.com/swaggo/http-swagger"
4

3. Utilizando a ferramenta Swag p/ fazer o parser e gerar a especificação OpenAPI

Neste ponto já posso chamar o `Swag`, que criará os arquivos necessários, p/ posteriormente chamarmos o Swagger UI, que é a página web que mostra a documentação que especificamos nos comentários das funções, e também inicio a API para que a página fique exposta na API.

Então novamente, os passos p/ gerar a documentão e iniciar o Swagger UI são:

1swag init
2go run main.go

Agora é possível access o Swagger UI através do endereço http://localhost:3001/swagger/

Adicionando endpoint /my-bike para o verbo [GET]

É tão claro e fácil, que agora somente lendo o código é possível identificar como gerar documentação através dos comentários funciona, e como a OpenAPI é simples e gostosa de trabalhar.

1
2// listMyBike
3// @Summary List My Bike
4// @Description List details of My Bike
5// @Tags listMyBike
6// @Accept json
7// @Produce json
8// @Success 200 {object} Bike
9// @Router /my-bike [GET]
10func listMyBike(w http.ResponseWriter, r *http.Request) {
11err := json.NewEncoder(w).Encode(myBike)
12if err != nil {
13log.Println(err)
14}
15}

Adicionando endpoint /my-bike para o verbo [POST]

Seguindo a ideia anterior, esta é a definição p/ o método POST:

1// createMyBike
2// @Summary Create a Bike
3// @Description Create a Bike
4// @Tags createMyBike
5// @Accept json
6// @Produce json
7// @param body body Bike true "Bike Object"
8// @Success 201 {object} Bike
9// @Router /my-bike [POST]
10func createMyBike(w http.ResponseWriter, r *http.Request) {
11	reqBody, err := ioutil.ReadAll(r.Body)
12	if err != nil {
13		log.Println(err)
14	}
15	defer r.Body.Close()
16	json.Unmarshal(reqBody, &myBike)
17	if err != nil {
18		log.Println(err)
19	}
20	w.Write([]byte("Bike created!"))
21}

Um exemplo completo e funcionando está disponível https://github.com/converge/my-bike-api.