Generate swagger specification from Go source code

If you have some API written in Go for which you want to generate some fancy swagger specification, well this article is just about that!

Image for post
Image for post
Created using gopherize.me

Why swagger?

We developers usually don’t enjoy that documentation part in our jobs that much. It looks boring, repetitive and not that enjoyable. However documentation is a “must” for any API. Here is why:

  • It improves user adoption. People use products they enjoy, as developer of APIs your end users are also developers. In order for them to enjoy your API and use it you need to provide them with good documentaion.
  • It saves time and cost. Both internal and external users of your API need some onboarding to get started using your product. Poor or no documentation means more time spent onboarding those users and probably handling their frustration!

So documentation is good but simply writing some markdown file is most of the time not enough. We want a tool that is standardized for the job, easy to share and descriptive enough. Well Swagger is the first such tool that comes to mind. It is kind of a de facto standard for documenting APIs.

Why not just write it by hand?

As developers we automate things. Well it feels natural to automate our own jobs as well, then.

Swagger docs are nice. For having one, all you need to do is to write a json or yaml file describing your API in term of URLs, requests and responses with a specific syntax. Then you will pass that specification to some other tool like swagger editor which will generate some amazing html and css out of it. In the following image you can see the specification on the left and the resulting documentation on the right:

Image for post
Image for post
A glance at a sample swagger documentation

Here’s what we gain by automating creation of swagger specification:

  • We will keep things simple (KISS). As developers we use tools. A lot of tools. Each tool adds some complexity, so do we want to go deep into details of some new tool (namely Swagger)? Most probably not.
  • We will avoid repetition (DRY). Most probably you have defined some data structures in your code to which you will map requests and responses of your APIs. So why bother with rewriting them with another syntax in your specification? We have all seen the headache following that kind of repetition I guess. If we don’t eliminate that repetition the docs are far more likely to fall out of sync and it’s extremely harder to maintain them.

Comparison of two tools for generating the spec

As of this writing the two dominant libraries for generating Swagger spec from go source code are Swag and go-swagger. Here I will discuss pros and cons of each and describe why I choose the second one.

  • Where Swag wins: convenience. Swag is simpler. You just put some comments for your handlers and everything works out of the box. go-swagger is a little more complicated in terms of what you need to do in order for your spec to get generated.
  • Where go-swagger wins: Power. go-swagger gives you more power and flexibility to describe your API. It gives you more control over what gets generated.
  • Where go-swagger wins: Readability of code. With Swag each of your APIs have some very lengthy comments with lots of annotations preceding them. The comments are sometimes even longer than the code itself! But with go-swagger you can isolate those comments from your code. This way comments in your code can focus on people actually developing it and comments from which swagger spec is generated will be kept in its own specific package. Here’s what happens to your code if you don’t have that isolation of swagger-related comments:
Image for post
Image for post
How each endpoint will look like with Swag
  • Where go-swagger wins: Popularity: go-swagger at the time of this writing has almost four times as many stars as Swag. It also seems better maintained and seems like it has less bugs. For example go-swagger supports representing 2D arrays in body of request/response while Swag does not. (at the time of this writing)

So how can I generate that spec?

I will go through a case study describing how you can use go-swagger to generate your swagger specification. But before we start please note that in order for go-swagger to work, your package should be located correctly under GOPATH (even if you use go modules) and you should have a vendor folder containing your dependencies. I will describe this in more detail later.

Well… first you need to have an API. Here is a simple API that takes a POST request and returns a response. Bodies of both requests and response are JSON.

A sample endpoint

Then we will create a separate package to hold the comments and structs written for the purpose of Swagger. We will name it docs . But before that in our main file main.go we need to add an import for our docs package. This is because without that import, the docs package is not imported anywhere in the code, therefore it will be ignored during the build. go-swagger starts looking for packages from main.go and follows is imports recursively. Therefore without such import there will be no docs for us! In our main file we also set up basic auth for all our endpoints.

So now that we have a simple application up and running we can go for the docs package and see what should go in there. In order to give general information about our APIs as a whole (not any endpoint in specific) we need to create a file in our docs package and add a package comment like this:

The comments are self descriptive and the conventions for writing it are described in this page. In short, then name that follows Package classification in the first line is name of our web service. The line following it is description of our API. There are some more info and the whole thing ends with swagger:meta annotation. This results in this part of our docs:

Image for post
Image for post
Output of meta annotation

Finally we document the foobar endpoint under docs package using just a few lines of comments and go code. Here is how it looks like:

A few things to point out about this snippet are:

  • swagger:route annotation is followed by an http method, a URL, a tag for that endpoint (endpoints with similar tags will be grouped together in resulting documentation) and an id for that endpoint. The id will be used for declaring parameters of the endpoint.
  • Line following swagger:route annotation is description of that endpoint. It should end with a dot in order for it to be properly displayed! If it ends with a dot it is displayed in summary of the endpoint in front of the url when the section for that endpoint is collapsed, otherwise it will only get visible when the section is expanded (not collapsed).
  • We define a struct for response body in case of success. We call it fooBarResponseWrapper . This struct has a single field called Body annotated with //in:body . Name of this struct does not make any difference. What matters is the name you put in front of swagger:response annotation. That name is used in responses section of swagger:route comments to indicate what response gets returned. Note that whatever comment you put above swagger:response annotation will be used as description of response body in docs. go-swagger will automatically figure out how JSON of api.FooBarRequest looks like and will display it in the docs.
  • We define a struct for parameters of requests called fooBarParamsWrapper . This specific endpoint has only a body parameter. (No path parameter or query parameter). Therefore the struct has a single field. Please note that the struct is annotated with // swagger:parameters idOfFooBarEndpoint This annotation is how go-swagger will figure out what endpoint there parameters belong to. The struct has a single field called Body annotated with // in:body . go-swagger will automatically figure out what JSON representation of api.FooBarRequest looks like and will show it in the docs. It will also take any comment directly above // in:body annotation as description of the parameter. Name of this struct is also of no importance.

This is the docs that get generated for this specific endpoint:

Image for post
Image for post
docs of foobar endpoint

What commands do I need?

First I should emphasize that you need to put your project under GOPATH properly.

If you already use vendor package, you are good to go, otherwise if you are using go modules run the following command to create one: GO111MODULE=on go mod vendor

Then go on and install go-swagger via:

GO111MODULE=off go get -u github.com/go-swagger/go-swagger/cmd/swagger

Finally to generate swagger specification and putting it in a file called swagger.yaml you need to run GO111MODULE=off swagger generate spec -o ./swagger.yaml --scan-models in the root of project.

To see the resulting documentation. (viewing the yaml file as a fancy webpage) you can run: swagger serve -F=swagger swagger.yaml

If the commands look complicated there’s a simpler way! Just create a file called Makefile in the root of your project and paste the following snippet into it:

Then you can simply use make swagger to generate the spec (i.e. swagger.yaml) and use make serve-swagger to view the resulting docs in a browser. Also instead of using make serve-swagger you can paste your yaml file into swagger editor.

Image for post
Image for post
Result of running make servce-swagger

Source code and go-swagger docs

You can find source code of case study presented in this article HERE. source code of go-swagger HERE and you can visit documentation of go-swagger which describes all its features in great details using THIS LINK.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store