Documenting Api With Swag

Think on this, you’ve finished developing a new API, and now have to write documentation to guide you when building client-side applications that consume the API. You start thinking of various ways to achieve this, and you lay out multiple alternatives like Swagger, Docusaurus, Postman and many more. You remember all the work involved in the API documentation phase and wonder if there are shortcuts to speed things up. You need to do this because who will use an API without any documentation?

One great tool for creating API documentation is Swagger because of its ease of creating, maintaining, and publishing API documentation. Swagger is a professional, open source toolset that helps users, teams, and enterprises easily create and document APIs at scale.

Some benefits of using Swagger in your next project include:

  • Allowing you to create, maintain, and publish API documentation quickly and easily.
  • Generating interactive documentation that allows you to validate and test API endpoints from your browser without third-party software.
  • Easily understandable by developers and non-developers
  • Functionality to generate API client libraries (SDKs) for various languages and frameworks directly from an OpenAPI specification. (this last point is very important)

Here you will learn how to create Swagger documentation for Go web APIs directly from the source code using annotations and Swag. In this article, we will build a demo web API with Go and Fiber, then create documentation for it using Swag.

Build a demo Go web API

Fiber is an Express inspired web framework built on top of Fasthttp, the fastest HTTP engine for Go. Designed to ease things up for fast development with zero memory allocation and performance in mind.

Now let’s build the web API for a basic “to do” application.

Step 1: Set up your development environment

Create a new Go project in your text editor or IDE and initialize your go.mod file. You are free to use any name for your package:

go mod init go-api-with-swarg
Step 2: Install Fiber

Install the Fiber web framework in your project. In the terminal, type the following:

go get -u github.com/gofiber/fiber/v2
Step 3: Set up a Gin server

Create a file named main.go and save the following code in it:

package main

import (
    "github.com/gofiber/fiber/v2"
    "net/http"
    "log"
)

func main() {
        // configure the Fiber server
        app := fiber.New()

        // run the Fiber server
        log.Fatal(app.Listen(":3000"))
}
Step 4: Create the getAllTodos route

Let’s create a todo type and seed the list with some data. Add the following code to the main.go file:

// todo represents data about a task in the todo list
type todo struct {
        ID   string `json:"id"`
        Task string `json:"task"`
}

// message represents request response with a message
type message struct {
        Message string `json:"message"`
}

// todo slice to seed todo list data
var todoList = []todo{
        {"1", "Learn Go"},
        {"2", "Build an API with Go"},
        {"3", "Document the API with swag"},
}

Create a route handler that will accept a GET request from the client then return all the items in the to do list.

Add the following code to the main.go file:

func getAllTodos(c *fiber.Ctx) error {
	c.Status(http.StatusOK)
	return c.JSON(todoList)
}

Register the getAllTodos handler to the Fiber router. Update the main function in main.go with the following code:

package main

import (
    "github.com/gofiber/fiber/v2"
    "net/http"
    "log"
)

func main() {
        // configure the Fiber server
        app := fiber.New()
        app.Get("/todo", getAllTodos)

        // run the Fiber server
        log.Fatal(app.Listen(":3000"))
}

Test the getAllTodos route by running the Fiber server and making a request via curl like so:

go run main.go
curl -X 'GET' \
  'http://localhost:3000/todo' \
  -H 'accept: application/json'
Step 5: Create the getTodoByID route

Create a route handler that will accept a GET request from the client and a todo ID, then return the details of the associated item from the todo list.

Add the following code to the main.go file:

func getTodoByID(c *fiber.Ctx) error {
	ID := c.Params("id")

	// loop through todoList and return item with matching ID
	for _, todo := range todoList {
		if todo.ID == ID {
			c.Status(http.StatusOK)
			return c.JSON(todo)
		}
	}

	// return error message if todo is not found
	r := message{"todo not found"}
	c.Status(http.StatusNotFound)
	return c.JSON(r)
}

Register the getTodoById handler to the Fiber router. Add the following code to the router configuration in main.go:

app.Get("/todo/:id", getTodoByID)

Test the getTodoById route by making a request via curl like so:

curl -X 'GET' \
  'http://localhost:3000/todo/2' \
  -H 'accept: application/json'
Step 6: Create the createTodo route

Create a route handler that will accept a POST request from the client with a todo ID and task, then add a new item to the todo list.

Add the following code to the main.go file:

func createTodo(c *fiber.Ctx) error {
	var newTodo todo

	// bind the received JSON data to newTodo
	if err := c.BodyParser(&newTodo); err != nil {
		r := message{"an error occurred while creating todo"}
		c.Status(http.StatusBadRequest)
		return c.JSON(r)
	}

	// add the new todo item to todoList
	todoList = append(todoList, newTodo)
	c.Status(http.StatusCreated)
	return c.JSON(newTodo)
}

Register the createTodo handler to the Fiber router. Add the following code to the router configuration in main.go:

app.Get("/todo", getAllTodos)

Test the createTodo route by making a request via curl like so:

curl -X 'GET' \
  'http://localhost:3000/todo' \
  -H 'accept: application/json'
Step 7: Create the deleteTodo route

Create a route handler that will accept a DELETE request from the client along with a todo ID, then remove the associated item from the todo list. Add the following code to the main.go file:

func deleteTodo(c *fiber.Ctx) error {
	ID := c.Params("id")

	// loop through todoList and delete item with matching ID
	for index, todo := range todoList {
		if todo.ID == ID {
			todoList = append(todoList[:index], todoList[index+1:]...)
			r := message{"successfully deleted todo"}
			c.Status(http.StatusOK)
			return c.JSON(r)
		}
	}

	// return error message if todo is not found
	r := message{"todo not found"}
	c.Status(http.StatusNotFound)
	return c.JSON(r)
}

Register the deleteTodo handler to the Fiber router. Add the following code to the router configuration in main.go:

app.Delete("/todo/:id", deleteTodo)

Test the deleteTodo route by making a request via curl like so:

curl -X 'DELETE' \
  'http://localhost:3000/todo/5' \
  -H 'accept: application/json'

Document the web API with Swag

Swag is middleware that helps to automatically generate RESTful API documentation with Swagger 2.0 for Go directly from source code using annotations. It requires you to specify how your routes work and automates the entire Swagger documentation creation process.

Swag is compatible with many Go web frameworks and has various integrations for them. This tutorial will use the Fiber integration.

Step 1: Install Swag

Install the Swag package in your project. In the terminal, type:

go get -u github.com/swaggo/swag/cmd/swag
go get -u github.com/swaggo/fiber-swagger
go get -u github.com/swaggo/files

Step 2: Initialize Swag

Initialize Swag in your project. In the terminal, type:

swag init

This will make Swag parse your annotations and generate the Swagger documentation for your code into the newly created docs folder.

If your terminal does not recognize swag init when executed, you need to add the Go bin folder to PATH.

Step 3: Import the Swag package into your project

Update the imports in the main.go file with the code below:

import (
	"log"
	"net/http"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/swagger"
	_ "github.com/jackgris/go-api-with-swarg/docs"
)

Step 4: Add general API annotations to the code

The General API annotations contain basic information about the API documentation (title, description, version, contact info, host, and license).

Add the following set of annotations to the main.go file (preferably before the main function):

//	@title			Go + Fiber Todo API
//	@version		1.0
//	@description	Sample todo server. You can visit the GitHub repository at https://github.com/jackgris/go-api-with-swarg

//	@contact.name	API Support
//	@contact.url	http://www.swagger.io/support
//	@contact.email	[email protected]

//	@license.name	Apache 2.0
//	@license.url	http://www.apache.org/licenses/LICENSE-2.0.html

//	@host						localhost:3000
//	@BasePath					/
//	@query.collection.format	multi

Swag also lets you define your General API annotations in another file. You can learn how to do that here.

Step 5: Add API operation annotations to controller code

API operation annotations contain how the controller works (description, router, request type, parameters, and response codes). Let’s see how to add annotations for the getAllTodos route.

Add the following annotations right before the getAllTodos function in the main.go file:

//	@Summary	get all items in the todo list
//	@ID			get-all-todos
//	@Produce	json
//	@Success	200	{object}	todo
//	@Router		/todo [get]

In the code above, we defined the following:

  • @Summary, the summary of what the route does
  • @ID, a unique identifier for the route (mandatory for every route)
  • @Produce, the route response data type
  • @Success 200, the response model for expected status codes
  • @Router /todo [get], the route URI and accepted request method

We will add annotations for the getTodoByID route. Add the following code right before the getTodoByID function in the main.go file:

// @Summary get a todo item by ID
// @ID get-todo-by-id
// @Produce json
// @Param id path string true "todo ID"
// @Success 200 {object} todo
// @Failure 404 {object} message
// @Router /todo/{id} [get]

annotated form of the getTodoByID route

Here, we specified to Swag that the route accepts a mandatory string parameter called id attached to the request path. It has the name todo ID with @Param id path string true “todo ID”.

Next, we will add annotations for the createTodo route. Add the following code right before the createTodo function in the main.go file:

// @Summary add a new item to the todo list
// @ID create-todo
// @Produce json
// @Param data body todo true "todo data"
// @Success 200 {object} todo
// @Failure 400 {object} message
// @Router /todo [post]

Here, we specified to Swag that the route accepts a mandatory todo parameter called data attached to the request body. It has the name todo data with @Param data body todo true “todo data”.

We will add annotations for the deleteTodo route. Add the following code right before the deleteTodo function in the main.go file:

// @Summary delete a todo item by ID
// @ID delete-todo-by-id
// @Produce json
// @Param id path string true "todo ID"
// @Success 200 {object} todo
// @Failure 404 {object} message
// @Router /todo/{id} [delete]

annotated form of the deleteTodo route

View and test the documentation

Now you have defined all the annotations for the server and routes, let’s view and test the documentation.

To generate the documentation from your code, run swag init again in the terminal.

We have to run swag init each time we update the annotations in the code, so the documentation is regenerated and updated accordingly. And also you can run swag fmt if you want to format your swagger comments.

We also have to register a route handler to the Fiber router responsible for rendering the Swagger documentation created by Swag. Add the following code to the router configuration in main.go:

app.Get("/swagger/*", swagger.HandlerDefault)

Now that we have configured the docs route, run the server and navigate to the /swagger URI in your browser and you’ll see the generated Swagger documentation.

go run main.go

Conclusion

This article showed you how to seamlessly generate Swagger documentation for web APIs built with Go using Swag. You can learn more about Swag from its official documentation.

We chose to use Swagger because of the numerous features and functionalities that make it easy to create and maintain documentation for web APIs.

The source code of the web API built and documented in this tutorial is available on GitHub for you to explore. Repository

This post is highly inspired by this I hope you also enjoy it.


See also