Setting Up Swagger Docs for Golang API
Tags: go, webdev, tutorial, api
Published: 2019-11-01 17:54:25


_Note: This was originally posted at [martinheinz.dev](https://martinheinz.dev/blog/9)_

In the previous post - [Building RESTful APIs in Golang](https://dev.to/martinheinz/building-restful-apis-in-golang-2e58) - we created RESTful API in _Golang_. Now, that we have our project ready to be used, we should show our users how to do so, otherwise - if they can't test it and view its features - they won't even touch it. 

Without meaningful documentation of our APIs as well as an ability to test its endpoints, users won't even bother trying to use it. Solution to that is writing documentation. However, writing it may take lots of time, which could otherwise used to develop more cool features for our applications... So, what do we do? - we generate _Swagger_ docs!

![Swagger Golang](https://thepracticaldev.s3.amazonaws.com/i/no67a7xkr3sg0oxoritf.png)

## Libraries
Let's start with libraries needed to create the _Swagger_ docs. I said libraries, but really just need one - [swag](https://github.com/swaggo/swag) - which is _Golang_ library that converts code annotations (comments) to _Swagger_ Documentation 2.0. Aside from _swag_ you will need a middleware/wrapper library for your web framework. In _swag_ docs there are [links to libraries for supported frameworks](https://github.com/swaggo/swag#supported-web-frameworks), which include both the simplest option of `net/http` which a lot of people like to use as well as _GIN_, which I use and which I will show here. Even though you might be using different web framework, the annotations are gonna be the same, so you can learn something here anyway.

It's also worth to mention, that there is alternative _Golang Swagger_ library - `go-swagger` which seems to be more popular and also quite a bit more powerful. I, personally, however prefer to `swaggo/swag` because of its simplicity. If you need more control over what gets generated you might want switch to  `go-swagger`.

## Docstrings
Now, for the annotations/comments/docstring or whatever you want to call it. It's really just bunch of comments before specific API function, which is used to generate the _Swagger_ docs.

Before we get to describing individual API endpoints, we need to first write general description for our whole project. This part of annotations lives in your `main` package, right before the `main` function:

_Note: All the examples below come from my repository [here](https://github.com/MartinHeinz/go-project-blueprint/tree/rest-api), where you can find runnable application with the Swagger UI/Docs included._

```golang
import (
    ...
	swaggerFiles "github.com/swaggo/files"
	"github.com/swaggo/gin-swagger"

	_ "github.com/MartinHeinz/go-project-blueprint/cmd/blueprint/docs"
)

// @title Blueprint Swagger API
// @version 1.0
// @description Swagger API for Golang Project Blueprint.
// @termsOfService http://swagger.io/terms/

// @contact.name API Support
// @contact.email martin7.heinz@gmail.com

// @license.name MIT
// @license.url https://github.com/MartinHeinz/go-project-blueprint/blob/master/LICENSE

// @BasePath /api/v1
func main() {
    ...
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    ...
}
```

Above you can see example of _General API Info_, which includes things like name, version, license, base URL etc. There are few more fields that you can include and they are listed [here](https://github.com/swaggo/swag#general-api-info) with some examples.

Apart from the annotations, we also need to import necessary libraries including blank import of our `docs` package that we have to generate (more on that later). One more thing we need to do, is to actually mount the _Swagger UI_ at some endpoint, here we use `"/swagger/*any`.

This is the part of UI, which the annotations above would produce:
<p align="center">
  <img src="https://res.cloudinary.com/martinheinz/image/upload/v1572266650/blog_posts/general_info_fit30p.png"/>
</p>

Now for the important part - annotations for API functions. These annotations precede each function that is wired in `main` to serve some endpoint, so when we serve endpoint like `v1.GET("/users/:id", apis.GetUser)`, we need to annotate it like this:

```golang
// GetUser godoc
// @Summary Retrieves user based on given ID
// @Produce json
// @Param id path integer true "User ID"
// @Success 200 {object} models.User
// @Router /users/{id} [get]
func GetUser(c *gin.Context) {
    ...
}
```

Most of these are pretty self-explanatory and this is really minimal set of annotations that you should include. One thing I want to highlight though, is the `models.User` being returned on success - this is a model of database table that lives in `models` package. By referencing it like this, we cause it to appear in _Swagger UI_ in the _models_ section:

<p align="center">
  <img src="https://res.cloudinary.com/martinheinz/image/upload/v1572266650/blog_posts/models_jjabkh.png"/>
</p>

And this is a section that we get for our endpoint:

<p align="center">
  <img src="https://res.cloudinary.com/martinheinz/image/upload/v1572266650/blog_posts/endpoint_no_auth_dfkwwk.png"/>
</p>
    
## Generate!

Finally, it's time to generate the docs! All you need is one command - `swag init`, this command needs to be ran from directory where `main` is, so for the [blueprint repository](https://github.com/MartinHeinz/go-project-blueprint/tree/rest-api/cmd/blueprint) I made, it would be `.../cmd/blueprint/`. This command will create package called `docs`, which includes both _JSON_ and _YAML_ version of our docs.

Even though this package is generated, I prefer to store it in _GitHub_, as it is imported in the `main` package and therefore it's necessary for application to run. If you want to avoid pushing this generated code to _GitHub_, you could for example write a _Makefile_ target, that would re-generate the _Swagger_ docs on-the-fly before application is built and ran. If you however, decide to push it _GitHub_, you might want to run the docs through `go fmt` as it's not necessarily formatted _"as it should be"_.

## Authentication

At this point, we could just run the application, look at our nice new _Swagger UI_ and call it a day. One thing that is missing though, is authentication for the API. If you leave _Swagger UI_ unauthenticated, then anybody can hit any endpoint they want, which might be very undesirable, if - for example - your data could be damaged by users. Even worse, you might expose sensitive information from your database to the whole internet. I think those are enough reasons to setup some simple authentication for our API and therefore, also _Swagger UI_, so how do we do it?

First of all, we need to actually implement the authentication. Here, is case of _GIN_, we create a very simple authentication middleware, which we attach to router group:

```golang
func auth() gin.HandlerFunc {  // Middleware function
	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")  // Retrieve the header
		if len(authHeader) == 0 {  // Check if it's set
			httputil.NewError(c, http.StatusUnauthorized, errors.New("Authorization is required Header"))
			c.Abort()
		}
		if authHeader != config.Config.ApiKey {  // Check if the API Key is correct
			httputil.NewError(c, http.StatusUnauthorized, fmt.Errorf("this user isn't authorized to this operation: api_key=%s", authHeader))
			c.Abort()
		}
		c.Next()
	}
}
```

By attaching the middleware to specific group(s) we can control what is and what is not authenticated, which is important because we - for example - don't want _Swagger UI_ itself to be authenticated.

_Note: I've omitted some of the code, to make the examples readable and easy to follow. For full code, see the `rest-api` branch in repository [here](https://github.com/MartinHeinz/go-project-blueprint/tree/rest-api)._

One more thing that we need to change in `main` module is annotations - more specifically, we need to add the `securityDefinitions` annotation:

```golang
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
func main() {
    ...
}
```

This annotation - as you can already guess - adds API key authentication through `Authorization` header to the _Swagger UI_. Apart from API key authentication you could also choose to use _basic_ authentication (`securitydefinitions.basic`) using username and password or some version of _OAuth2_ (`securitydefinitions.oauth2`), all options are shown in documentation [here](https://github.com/swaggo/swag#security). I personally like to use API key as it is simple and the most convenient option in my opinion.

For _Swagger_ to recognize, that some endpoint is authenticated, we also need to add security annotation to said API function:

```golang
// @Security ApiKeyAuth
func GetUser(c *gin.Context) {
    ...
}
```

This was the last step and now (after regenerating _Swagger_ docs) we can finally run our application:

```console
foo@bar:~$ docker run -p 1234:1234 \
               -e BLUEPRINT_DSN="postgres://<USER>:<PASSWORD>@<DOCKER_SERVICE/URL>:<PORT>/<DB>?sslmode=disable" \
               -e BLUEPRINT_API_KEY="api_key" \
               docker.pkg.github.com/martinheinz/go-project-blueprint/blueprint:latest
```

And you should see something like this in _GIN_ logs:

```shell
[GIN-debug] GET    /swagger/*any             --> github.com/swaggo/gin-swagger.CustomWrapHandler.func1 (3 handlers)  # <- Swagger is ready!
[GIN-debug] GET    /api/v1/users/:id         --> github.com/MartinHeinz/go-project-blueprint/cmd/blueprint/apis.GetUser (4 handlers)
```

We can now open the _Swagger UI_ at <http://localhost:1234/swagger/index.html> and test our documentation!

_Note: If the command above doesn't make much sense to you, please consider also reading through previous post [here](https://dev.to/martinheinz/building-restful-apis-in-golang-2e58)._

So, just to recap - the security definition in `main` package gives us following modal:

<p align="center">
  <img src="https://res.cloudinary.com/martinheinz/image/upload/v1572266650/blog_posts/auth_modal_empty_ix7gkl.png"/>
</p>

Then, if we enter incorrect API key (`"wrong_api_key"`) we get _401_ response code:
<p align="center">
  <img src="https://res.cloudinary.com/martinheinz/image/upload/v1572266650/blog_posts/401_wrong_api_key_wn8ntt.png"/>
</p>

And if we use correct API key we get back _200_ with the data requested:
<p align="center">
  <img src="https://res.cloudinary.com/martinheinz/image/upload/v1572266650/blog_posts/200_correct_api_key_l35jd0.png"/>
</p>

It's important to also mention, that sending authorization headers in plaintext like we have done here is not secure whatsoever and defeats the whole purpose of authenticating the API, so in real application you should definitely use HTTPS.

## Conclusion

After reading this article, I hope you now know, how to go about setting up _Swagger_ docs for your API and I also hope that you will actually write some docs for your next project as it's pretty simple and there's great value in good API documentation for both you (manual testing) and users of your application. You can checkout full code in my repository's `rest-api` branch [here](https://github.com/MartinHeinz/go-project-blueprint/tree/rest-api) and if you have questions or improvements, feel free to reach out to me or create issue/pull request in the repository. &#x1F642;