Got Swagger? (i.e. How I Got My Swagger on and How You Can Too)

Aaron Diffenderfer Programming, Technology Snapshot, Tutorial Leave a Comment

Most developers attempt to ignore and put off documentation as long as possible during the development process. (Perhaps more than any other part of the process – well, in addition to unit testing.) However, the return on investment for documentation is definitely worth the time and effort, far more than most of us realize. This is particularly true with API documentation. 

Working with a recent client, I had the opportunity to use Swagger to document APIs and provide structure around the development process. During daily standups, I may have been known to say that my task for the day was to “get my Swagger on.” In this post, I want to walk you through my journey with Swagger along with some general thoughts, tips, and tricks I have learned along the way so that you too can “get your Swagger on.”

What?

While originally known as “Swagger RESTful API Documentation Specification,” it is now officially referred to as the “OpenAPI Specification.” (Though I prefer and still refer to it as Swagger both for simplicity and for fun.)

It is not the typical documentation structure of random comments or blobs of text that have been stored in a wiki page somewhere (i.e. not your parents’ documentation format of the past few decades). The specification uses actual code as the documentation, whether in the form of JSON or YAML. 

My personal preference is JSON for the clear code structure that it provides. (I’ve included some JSON code samples later on in this post.) Swagger makes you feel like you are coding when in reality you’re documenting, so you get the best of both worlds.

Why?

As I began working with Swagger, I started by conducting some comparisons with other similar specifications just to have a better understanding of what was available, how they all worked, and to make sure that’s really what I wanted to use. There are numerous opinions as to which specification is best or why to choose one over the other.

In my case, I wanted to accomplish two primary goals:
1) standardize documentation formats across teams and projects, and
2) have the ability to easily test and validate the endpoints.

RAML and API Blueprint are two of the other main players in the API documentation arena. Pact is a lesser known option, but I like the “consumer-driven contract” concept that it is based on. In comparison to the others, however, Pact isn’t widely adopted and consequently not contributed to as actively. And it is primarily geared toward testing rather than documentation, which didn’t align with my two goals. 

All of the specifications have their pros and cons, yet accomplish the main goal of a standardized format. Swagger continues to evolve quickly and grow both in abilities and in industry backing. It is open source with great community support and tooling as well. So, in the end, it was a fairly easy selection.

How?

With Swagger, there are two basic approaches of how and when to do the documentation: code-first or contract-first. 

See Also:  JMeter Performance and Load Testing

For code-first, the OpenAPI Specification includes numerous libraries that can be incorporated directly into your code (integrating with pretty much any language). The API documentation is then generated from your annotations, comments, etc. 

The contract-first approach drives from the idea that you write the documentation and then code the application (backend and frontend) to match. This is very similar to the ideology of test-driven development and other development processes.

Personally, I’m a proponent of the contract-first approach for many reasons. In some circumstances, the teams writing the front-end may be different from those writing the back-end, so writing an API definition first puts everyone on the same page up front and helps to ensure a consistent approach throughout development. With code-first, if the back-end team makes a change, the front-end folks won’t be aware until the documentation is generated or the code breaks – unless the teams have excellent communication and someone lets them know in advance. (That really happens with some teams, right?) 

If the frontend and backend teams are one in the same, or maybe even just the same singular developer, the contract-first approach assists in the initial planning and preparation. The contracts can still change, but they are at least documented and can be updated by everyone as needed which fits in well with the Agile mindset of being flexible and adapting as you develop.

On the teams I’ve been involved with, we even use Swagger as the foundation for API meetings. We start writing out what endpoints we think are needed, the parameters, responses, a few sample responses, etc. So, Swagger, with its structure, even helps in driving conversations.

Tips and Tricks

There is a lot of information available about how to use the OpenAPI Specification throughout the comprehensive documentation, github, stackoverflow, and other sites. However, as I’ve worked through various scenarios, there have still been some situations where it wasn’t blatantly obvious as to what was needed to achieve a particular design without me doing a lot of extra digging and experiencing some trial and error with the editor and validators. So here are a few examples and tips with “getting your Swagger on.”

Developing a Generic Response Object

Swagger allows you to reference separate files, so you can store the response description and other common definitions in a separate file and reference them within the main specification. However, be aware that the online Swagger editor won’t be able to understand any exterior references.

Example:

"responses": 
    {
        "200": {
            "description": "success",
            "schema": {
              "$ref": "#/definitions/aSpecificResponse"
            }
        }
    }

"definitions": {
    "aSpecificResponse": {
        "allOf": [
            {
                "$ref": "#/definitions/aGenericResponse"
            },
            {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/definitions/someDataObject"
                    }
                },
                "required": [
                    "data"
                ]
            }
        ]
    },
    "aGenericResponse": {
        "type": "object",
        "properties": {
            "info": {
                "type": "string",
                "description": "An informational message from the server",
                "example": "Found 5 <item>"
            },
            "totalItems": {
                "type": "integer",
                "format": "int64",
                "description": "Number of items retrieved",
                "example": 5
            },
            "serverStatus": {
                "type": "string",
                "description": "The response from the server.",
                "example": "SUCCESS"
            }
        },
        "required": [
            "info",
            "totalItems",
            "serverStatus"
        ]
    }
}
Creating Reusable Swagger Definitions

This is great for defining parameters and objects that are used often. It makes it easier to change all instances in one common location later as needed.

See Also:  What's New in JUnit 5.2

Following this suggestion may not fully align with the code-first stance. The Swagger objects you define, particularly if you create very granular and reusable elements, may not match up perfectly one-to-one to your code structure. This is fine since the focus here with contract-first is on the documentation and not the code that is developed.

Variable Keyed Objects Are Possible

If you want to define a map, dictionary, key/value pair, etc, where the key can be different, then additionalProperties are to the rescue.

In this example, the key is the phone number which isn’t even defined in the structure and the value is the entry. This will generate a key value pair with a generic key and a value with entry.

Example:

"phonebook": {
    "type": "object",
    "description": "The phone book",
    "additionalProperties": {
        "$ref": "#/definitions/entry"
    }
},
"entries": {
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "description": "The name of the business.",
            "example": "ACME Enterprises"
        },
        "address": {
            "$ref": "#/definitions/address"
        }
    },
    "required": [
        "name"
    ]
},
Provide Data Examples

This is extremely useful for generating sample responses within the documentation to further aid developers.

Note: Be aware that some documentation generators may need enhancements to make the examples display in a more meaningful manner.

Example:

"person": {
    "type": "object",
    "properties": {
        "firstName": {
            "type": "string",
            "description": "The first name",
            "example": "Aaron"
        },
        "lastName": {
            "type": "string",
            "description": "The last name",
            "example": “Diffenderfer"
        },
        "address": {
            "$ref": "#/definitions/address"
        }
    },
    "required": [
        "firstName",
        "lastName"
    ]
},

Final Thoughts

To further enhance the coding and documentation cross-experience, I ended up extending the swagger-codegen project to generate specific wiki documentation for the project. 

Some of the data examples and other content that was initially generated didn’t have the usefulness nor the look and feel that I wanted, so I enhanced the code to accomplish the markup and layout necessary.

That part is beyond the scope of this particular blog post, but it gives you a good indication that in spite of the usual dull and boring documentation topic, Swagger allows you to stay within the wonderful world of coding while still performing a critically important part of the development process.

You might also check out how Swagger/OpenAPI documentation can be automatically published to an API documentation portal.

Now go get your Swagger on!

What Do You Think?