DEV Community

Cover image for Documenting a Go API with OpenAPI 3 Standard: A Practical Guide
Ekemini Samuel
Ekemini Samuel

Posted on

Documenting a Go API with OpenAPI 3 Standard: A Practical Guide

APIs have become an integral part of modern software development, allowing applications to communicate with each other and exchange data. However, building an API is only half the battle. Without proper documentation, developers may struggle to understand how to use the API, leading to wasted time and resources. This is where API documentation comes in.

OpenAPI is a widely used specification for describing RESTful APIs. With its powerful schema and documentation capabilities, it is now the de facto standard for API documentation. In this article, we will explore the importance of API documentation, introduce OpenAPI, and provide examples of how to write OpenAPI documentation using Go.

Let's dive in!

What is an API?

An API, or Application Programming Interface, is a set of protocols, routines, and tools for building software applications. APIs allow different applications to communicate with each other, making it easier to share data and functionality. APIs can take many different forms, including RESTful APIs, SOAP APIs, and GraphQL APIs.

RESTful API

RESTful APIs adhere to the principles of Representational State Transfer (REST). RESTful APIs use HTTP requests to interact with web resources and represent resources as URLs. This makes it easy to use standard HTTP verbs such as GET, POST, PUT, and DELETE to manipulate resources.

SOAP API

A SOAP API, (Simple Object Access Protocol) is a protocol for exchanging XML-based messages over a network. It uses a set of rules for sending and receiving messages, and is typically used in enterprise-level applications.

GraphQL API

GraphQL is a newer API technology that provides a more flexible way of requesting data. It allows developers to send a single request to the server, specifying the exact data they need. This can help reduce the number of requests needed to retrieve data, and can improve performance.

Why Document APIs?

Clear and concise documentation is essential for any API. It can improve adoption and developer experience, leading to faster development times and improved quality.
Proper API documentation should include a description of the API, its endpoints, and its input and output parameters. It should also be written with the target audience in mind and include examples of how to use the API, along with any error codes that may be returned.

Introducing OpenAPI

OpenAPI was formerly known as Swagger and has since become the standard for API documentation. OpenAPI allows you to define your API using a JSON or YAML file and provides a wide range of documentation features.

The key components of an OpenAPI specification include:

  • Info: This provides basic information about the API, including its title, version, and description.

  • Paths: The Paths define the different endpoints of the API, along with their input and output parameters.

  • Parameters: This defines the input and output parameters for each endpoint, including their data type and any restrictions.

  • Responses: This defines the different responses that can be returned by the API, including their status codes and any error messages.

Best practices for writing OpenAPI 3 documentation

Now that we have a basic understanding of OpenAPI, let's look at how we can use it to document APIs. Writing documentation is not an easy task, but OpenAPI provides a clear and structured way of describing APIs. Some best practices include:

  • Use clear and concise language: Avoid using technical jargon on technical terms that may not be familiar to the intended audience.

  • Provide examples and use cases: This helps developers understand how to use the API in real-world scenarios.

  • Use formatting and organization: Use headings, bullet points, and other formatting options to make the documentation easy to read and navigate.

  • Keep the documentation up to date: As the API changes, so should the documentation. Make sure to keep it up to date so that it remains a useful resource.

An Example of Documenting APIs with OpenAPI 3 in Go

Let's say we have an API that allows users to retrieve information about books. Here's how we can use OpenAPI 3 to document it:

  • The main.go file that contains the Go API:
package main

import (
    "log"
    "net/http"
    "strconv"

    "github.com/go-chi/chi"
    "github.com/go-chi/chi/middleware"
    "github.com/go-chi/render"
)

type Book struct {
    ID     int    `json:"id"`
    Title  string `json:"title"`
    Author string `json:"author"`
}

var books = []Book{
    {1, "The Go Programming Language", "Alan A. A. Donovan, Brian W. Kernighan"},
    {2, "Designing Data-Intensive Applications", "Martin Kleppmann"},
    {3, "Code Complete", "Steve McConnell"},
}

func main() {
    r := chi.NewRouter()
    r.Use(middleware.Logger)
    r.Use(render.SetContentType(render.ContentTypeJSON))

    r.Get("/books/{id}", GetBook)

    log.Println("Starting server on :3000")
    http.ListenAndServe(":3000", r)
}

func GetBook(w http.ResponseWriter, r *http.Request) {
    bookID := chi.URLParam(r, "id")
    for _, book := range books {
        if strconv.Itoa(book.ID) == bookID {
            render.JSON(w, r, book)
            return
        }
    }
    render.Status(r, http.StatusNotFound)
}


Enter fullscreen mode Exit fullscreen mode
  • And here is the corresponding book.yaml file that documents the API using OpenAPI 3 standard:
openapi: 3.0.0
info:
  title: Book API
  description: API for retrieving information about books
  version: 1.0.0
servers:
  - url: http://localhost:3000
    description: Local server
paths:
  /books/{id}:
    get:
      summary: Get a book by ID
      description: Returns a single book object by ID
      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true
          description: ID of the book to retrieve
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Book'
        '404':
          description: Book not found
          content: {}
components:
  schemas:
    Book:
      type: object
      required:
        - id
        - title
        - author
      properties:
        id:
          type: integer
          format: int64
          description: Unique identifier of the book
        title:
          type: string
          description: Title of the book
        author:
          type: string
          description: Author of the book

Enter fullscreen mode Exit fullscreen mode

The book.yaml file defines the API version, the base URL, and the paths for each endpoint. It also specifies the HTTP methods allowed for each endpoint, such as GET, POST, PUT, DELETE, and so on. For example, the GetBook endpoint is defined in the YAML file with the following details:

  /books/{id}:
    get:
      summary: Retrieve a book by ID
      description: Retrieve the book with the given ID from the library.
      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true
          description: Numeric ID of the book to retrieve.
      responses:
        '200':
          description: A book object.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Book'
        '404':
          description: The specified book was not found.

Enter fullscreen mode Exit fullscreen mode

This definition specifies that the endpoint is a GET method that retrieves a book by ID. It also specifies the parameters that the endpoint accepts and the responses that it returns. In this case, the GetBook endpoint returns a JSON object representing a book, or a 404 error if the specified book is not found.

The book.yaml file also includes definitions of the data models used by the API. For example, the "Book" object is defined as follows:

components:
  schemas:
    Book:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        author:
          type: string
      required:
        - id
        - title
        - author

Enter fullscreen mode Exit fullscreen mode

This definition specifies that the Book object is an object that has three properties: id, title, and author. The id property is an integer, while the title and author properties are strings. It also specifies that all three properties are required.

Let's break down the key components of the YAML file specification for the Go book API above:

  • openapi: specifies the version of the OpenAPI specification being used.

  • info: provides metadata about the API, including the title, description, version, and contact information.

  • servers: defines the server information including the URL and description.

  • paths: defines the available endpoints(routes) of the API, including the HTTP method used to access each endpoint, and the request and response parameters for each endpoint.

  • components: defines reusable schema, parameters, responses, and security schemes used in the API.

  • security: defines the security schemes used to secure the API and which endpoints require authorisation.

  • tags: provides metadata about the API paths, including a brief description and an optional external documentation link.

  • responses: defines the possible responses that the API can return, including the response code, description, and the content schema.

  • requestBody: defines the expecterd request body for an endpoint, including the content type and content schema.

  • parameters: defines the parameters that can be used in the path, query, header, or cookie of a request, including the type, description, and default value.

  • 200: this component specifies the response when the request is successful with a status code of 200.

Once we have created the OpenAPI specification file, we can use it to generate documentation in various formats, such as HTML, PDF, or Markdown. There are many tools available for generating documentation from OpenAPI specifications, such as Swagger UI, ReDoc, and Slate.

By defining the API endpoints and data models in the OpenAPI 3 specification file, the file provides a comprehensive documentation of the API that can be used to generate code, test cases, client libraries, server stubs, and interactive API documentation. This not only makes it easier for developers to understand and use the API, but also saves time and effort in the long run.

This is just one example of how OpenAPI can be used to document an API in Go. There are many other ways to write OpenAPI specifications and integrate them into your application. The exact approach may differ depending on the specific API being documented and the desired output format.

Testing the Book API

To test the Go book API and run it locally, you can follow these steps:

  1. In your terminal or code editor, navigate to the project directory.

  2. Run the go mod init <module_name> to create a new Go module.

  3. Run the command go install github.com/go-chi/chi/v5 to install the package.
    Once the package has been installed, you should be able to import it into your Go code and use its functions and methods.
    Note: Go version 1.18, no longer installs packages with the go get command. Instead, we use the go install command.

  4. Then we run the main.go file to start the server. Following our program above, it will be listed on port :3000

  5. We can then test the API on the terminal, Postman or ReqBin. (I used ReqBin, it is an online API testing tool for REST and SOAP APIs, works directly from your browser.)

  • In the terminal, we can use the cURL tool to make requests to the API. To make a request to the /books/1 endpoint, run this command in your terminal:
curl http://localhost:3000/books/1
Enter fullscreen mode Exit fullscreen mode

This should return a JSON response containing an array of books.

  • To make requests using ReqBin, set the request method to GET, and set the request URL to http.//localhost:3000/books/1. You can then send the request and view the response in the "Response" tab.

This is a screenshot of when I tested the Go book API using ReqBin.
The box highlighted in 'Magenta' is for the GET request URL, while the one highlighted in 'Red-orange' is for the 'Response'

a screenshot of when I tested the Go book API using ReqBin

Tools for Documenting APIs

Once you have created your API documentation, it is important to choose the right tool to present it to your users. There are many tools available for documenting APIs, each with its own strengths and weaknesses. Some of the most popular tools for documenting APIs include:

  • Swagger UI: Swagger UI is a popular open-source tool for documenting REST APIs. It allows you to create interactive documentation for your API using OpenAPI, and provides a user-friendly interface for exploring your API.

  • Postman: Postman is a popular API development environment that can also be used for API documentation. It allows you to create documentation for your API using Markdown, and provides a user-friendly interface for exploring your API.

  • OpenAPI Generator: The OpenAPI generator is a code generator that can automatically create documentation for your API using the OpenAPI specification. This specification is a standardised format for describing RESTful APIs, which makes it easy to generate documentation in a consistent and predictable way. The OpenAPI generator supports a wide range of programming languages, including Go, Java, Python, and many others.

  • Readme: Readme is a popular documentation platform that can be used for API documentation. It provides a user-friendly interface for creating and publishing API documentation, and supports both OpenAPI and Swagger.

  • ReDocly: ReDocly is an open-source tool for creating API documentation. It allows you to create documentation for your API using OpenAPI, and provides a user-friendly interface for exploring your API.

When choosing a tool for documenting your API, it is important to consider your specific needs and requirements. Some important factors to consider include:

  • Ease of use: Is the tool user-friendly and easy to navigate? Can users easily find the information they need?

  • Customisation: Can you customize the look and feel of the documentation to match your brand?

  • Integration: Can the tool integrate with other tools and platforms, such as GitHub, Jira, or Slack?

  • Collaboration: Does the tool allow for collaboration between team members, such as commenting or version control?

  • Scalability: Can the tool scale with your API as it grows and evolves?

Regardless of the tool you choose, investing time and effort into creating good API documentation is well worth the effort, and will pay off in the long run.

Conclusion

Documenting APIs is an essential part of software development, and OpenAPI provides a powerful and flexible way to create clear and concise API documentation. By following best practices for writing documentation and using API documentation tools, you can make your API more accessible to other developers and improve their overall experience. With the increasing popularity of RESTful APIs and the growth of the API economy, it's more important than ever to invest time and resources into creating high-quality API documentation.

I hope this article has provided a useful introduction to API documentation and OpenAPI, as well as practical tips and examples for how to use OpenAPI 3 specifications to document APIs in Go. By following these guidelines and best practices, you can create APIs that are well-documented, easy to use, and more widely adopted by other developers.

Feel free to reach out, or drop your questions in the comment section below.

We can also connect on LinkedIn and Twitter.
Happy coding! 👨‍💻🚀

Image by pikisuperstar on Freepik

Oldest comments (2)

Collapse
 
danielgtaylor profile image
Daniel G. Taylor

Awesome introduction to OpenAPI and how it can be used for Go APIs!

I just wanted to point out that you can use Huma (disclaimer: I'm the author) to automate some of this process when building Go services. It adds a simple OpenAPI 3.1 & JSON Schema layer on top of a bunch of routers (including Go 1.22's built-in ServeMux), gives you compile-time checks of static typed requests/responses, built-in validation with exhaustive structured error responses, supports client-driven content negotiation, and more.

Here's an article with some more info: dev.to/danielgtaylor/apis-in-go-wi...

Collapse
 
envitab profile image
Ekemini Samuel

Hi Daniel,

Thanks for reading and also sharing Huma - great work you did.

I checked it out and it's cool, looking forward to working with it soon :)