DEV Community

João Vanzuita
João Vanzuita

Posted on

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

mkdir seu-projecto
cd $_
go mod init github.com/<seu-user>/seu-projeto
Enter fullscreen mode Exit fullscreen mode

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.

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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:

r.Get("/swagger/*", httpSwagger.WrapHandler)
Enter fullscreen mode Exit fullscreen mode

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

// @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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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

func version(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("version: 1.0.0"))
}
Enter fullscreen mode Exit fullscreen mode

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

// version godoc
// @Summary Get API version
// @Description Get API version
// @Tags version
// @Accept  json
// @Produce  json
// @Success 200 {object} string
// @Router / [get]
Enter fullscreen mode Exit fullscreen mode

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:

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
Enter fullscreen mode Exit fullscreen mode

E adiciono os importes:

_ "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"
Enter fullscreen mode Exit fullscreen mode

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:

swag init
go run main.go
Enter fullscreen mode Exit fullscreen mode

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.

// 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)
}
}
Enter fullscreen mode Exit fullscreen mode

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

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

// 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!"))
}
Enter fullscreen mode Exit fullscreen mode

Um exemplo completo e funcionando está disponível aqui

Top comments (0)