Gerando Especificação OpenAPI com Go Lang e Swagger
Published: 2021-05-24 21:03:09

---
title: Gerando Especificação OpenAPI com Go Lang e Swagger
published: true
description: Especificação OpenAPI e Swagger sendo integrados para gerar a especificação a partir de comentários, utilizando Go Lang.
tags: 
//cover_image: https://miro.medium.com/max/580/1*IPeXKrUt5pSTHDtBLnhXPA.png
---

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 principais 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:

```bash
mkdir seu-projecto
cd $_
go 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](https://github.com/go-chi/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.

```go
func main() {
	r := chi.NewRouter()
	r.Get("/", version)
	fmt.Println("API listening at port 3001...")
	err := http.ListenAndServe(":3001", r)
	if err != nil {
		log.Fatal(err)
	}
}
```

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:

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

E adiciono a especificação OpenAPI p/ a função main, que ficará:
```go
// @title Titulo da sua API
// @version 1.0
// @description Descricão longa da sua API
// @termsOfService http://swagger.io/terms/
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:3001
// @BasePath /
func main() {
    r := chi.NewRouter()
    r.Get("/", version)
    r.Get("/swagger/*", httpSwagger.WrapHandler)
    fmt.Println("API listening at port 3001...")
    err := http.ListenAndServe(":3001", r)
    if err != nil {
        log.Fatal(err)
    }
}
```

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

```go
func version(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("version: 1.0.0"))
}
```

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

```go
// version godoc
// @Summary Get API version
// @Description Get API version
// @Tags version
// @Accept  json
// @Produce  json
// @Success 200 {object} string
// @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:*

```bash
go get -u github.com/go-chi/chi/v5
go get -u github.com/swaggo/swag/cmd/swag
go get -u github.com/swaggo/http-swagger
```

*E adiciono os importes:*

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

#### 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:

```bash
swag init
go 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.

```go
// listMyBike
// @Summary List My Bike
// @Description List details of My Bike
// @Tags listMyBike
// @Accept json
// @Produce json
// @Success 200 {object} Bike
// @Router /my-bike [GET]
func listMyBike(w http.ResponseWriter, r *http.Request) {
err := json.NewEncoder(w).Encode(myBike)
if err != nil {
log.Println(err)
}
}
```

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

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

```go
// createMyBike
// @Summary Create a Bike
// @Description Create a Bike
// @Tags createMyBike
// @Accept json
// @Produce json
// @param body body Bike true "Bike Object"
// @Success 201 {object} Bike
// @Router /my-bike [POST]
func createMyBike(w http.ResponseWriter, r *http.Request) {
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err)
	}
	defer r.Body.Close()
	json.Unmarshal(reqBody, &myBike)
	if err != nil {
		log.Println(err)
	}
	w.Write([]byte("Bike created!"))
}
```

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