Designing a Swagger API

The goal of Swagger is to define a standard interface for describing REST APIs. In an ideal world, a Swagger definition for your API will allow both humans and computers to discover and understand your API. At it’s core, Swagger is a formal specification of an API. Surrounding this specification are a wide swath of tools to support creating documentation, providing client libraries, and managing API deployments.

One of Swagger’s original goal was to provide a way to document an API in both a human and machine readable way. Swagger provides such a documentation format for RESTful APIs. By augmenting this documentation format with tools for API clients and developers, Swagger grew into an ecosystem providing for API developers and consumers.

Swagger provides a number of benefits over rolling your own API specification and solution. First, it provides a common language for describing RESTful APIS. Second, that common language is both human and machine readable. This common language can then be used by the ecosystem of Swagger tools to generate documentation, build client and server libraries, and integrate with Swagger aware deployment tools.

In this article, I will show how to use Swagger to develop an API, generate the documentation, and deploy the API to Amazon’s API Gateway, providing a complete end-to-end example of how to use Swagger to facilitate API design and maintenance.

The API

Let’s begin by defining the specification for the API. I will use a simple example from a previous article on hypermedia to define our Swagger API. In this example, we have a hypothetical API for managing a Player resource derived from the GKPlayer class used by Apple’s GameCenter API. The Player resource can be expressed with this simple diagram.

Player Resource

Representing this as a typical JSON response would yield something like the following.

GET https://api.example.com/player/1234567890
{
    "playerId": "1234567890",
    "alias": "soofaloofa",
    "displayName": "Kevin Sookocheff",
    "profilePhotoUrl": "https://api.example.com/player/1234567890/avatar.png"
}

And the list of this player’s friends could be retrieved with a separate API call.

GET https://api.example.com/player/1234567890/friends
[
{
    "playerId": "1895638109",
    "alias": "sdong",
    "displayName": "Sheldon Dong",
    "profilePhotoUrl": "https://api.example.com/player/1895638109/avatar.png"
},
{
    "playerId": "8371023509",
    "alias": "mliu",
    "displayName": "Martin Liu",
    "profilePhotoUrl": "https://api.example.com/player/8371023509/avatar.png"
}
]

Let’s take a look at how this API can be represented using a Swagger specification.

Writing the Swagger Specification

Swagger allows you to specify your API using JSON or YAML (a superset of JSON). Swagger is modelled closely after the JSON Schema specification, with some omissions and restrictions specific to supporting RESTful APIS.

By convention, the Swagger specification file is named swagger.json or swagger.yaml. Go ahead and create your swagger file now.

$ touch swagger.json

Info

A Swagger specification begins with a root document object called the Swagger object. In JSON your document would begin with this object specifying the version of the Swagger specification we are using, and a required info field that provides metadata for your API. In our case, we are using the 2.0 version of the Swagger specification. The info field is described by an “Info Object” containing a title and a version at a minimum. You can also include a short description of your API and links to contact information, terms of service, or licensing information.

We can use this as the basis for describing our API using JSON:

{
    "swagger": "2.0",
    "info": {
        "title": "Player API",
        "description": "A simple API for Player resources",
        "version": "1.0.1",
        "contact": {
            "name": "Kevin Sookocheff",
            "url": "https://sookocheff.com",
            "email": "kevin@sookocheff.com"
        },
        "license": {
            "name": "Apache 2.0",
            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
        },
        "termsOfService": "https://sookocheff.com/terms"
    }
}

Paths

In Swagger, the paths field specifies the available paths and operations for the API. Path names must begin with a slash. Paths also allow templating, where any variable portion of the path can be enclosed in curly braces. For example, we could specify a simple GET endpoint for retrieving a player by player id using Swagger.

GET https://sookocheff.com/player/1234567890
{
    "/player/{id}" : {
        "get": {
            "description": "Returns a player by player id",
            "produces": [
                "application/json"
            ],
            "responses": {
                "200" {
                    "description": "A player resource.",
                    "schema": {
                        "$ref": "#/definitions/Player"
                    }
                }
            }
        }
    }
}

This API produces a JSON response, as specified by the produces field, which is a list of supported MIME types that the API can produce. The specification also includes a “Response Object” that describes the expected format of the response. In this example, the response object is a reference to a predefined definition. These predefined objects can be used in multiple places within your API.

Definitions

Predefined objects are listed under the definitions field in the specification. Each object listed under the definitions field is a described using a subset of the JSON Schema specification with additional extensions for providing documentation. This is best viewed through an example describing our Player resource, full documentation can be found here.

"definitions": {
    "Player": {
        "type": "object",
        "properties": {
            "playerId": {
                "type": "string"
            },
            "alias": {
                "type": "string"
            },
            "displayName": {
                "type": "string"
            },
            "profilePhotoUrl": {
                "type": "string"
            }
        }
    },
    "required": ["playerId", "alias"]
}

A Complete GET Endpoint

Putting everything together, we end up with the following JSON describing the root API and the single GET endpoint.

{
    "swagger": "2.0",
    "info": {
        "title": "Player API",
        "description": "A simple API for Player resources",
        "version": "1.0.1",
        "contact": {
            "name": "Kevin Sookocheff",
            "url": "https://sookocheff.com",
            "email": "kevin@sookocheff.com"
        },
        "license": {
            "name": "Apache 2.0",
            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
        },
        "termsOfService": "https://sookocheff.com/terms"
    },
    "paths": {
        "/player/{id}" : {
            "get": {
                "description": "Returns a player with the identifier provided in the path",
                "produces": [
                    "application/json"
                ],
                "responses": {
                    "200": {
                        "description": "A player resource.",
                        "schema": {
                            "$ref": "#/definitions/Player"
                        }
                    }
                }
            }
        }
    },
    "definitions": {
        "Player": {
            "type": "object",
            "properties": {
                "playerId": {
                    "type": "string"
                },
                "alias": {
                    "type": "string"
                },
                "displayName": {
                    "type": "string"
                },
                "profilePhotoUrl": {
                    "type": "string"
                }
            },
            "required": ["playerId", "alias"]
        }
    }
}

Or, in YAML syntax:

swagger: '2.0'
info:
  title: Player API
  description: A simple API for Player resources
  version: 1.0.1
  contact:
    name: Kevin Sookocheff
    url: https://sookocheff.com
    email: kevin@sookocheff.com
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  termsOfService: https://sookocheff.com/terms
paths:
  "/player/{id}":
    get:
      description: Returns a player with the identifier provided in the path
      produces:
      - application/json
      response:
        '200':
          description: A player resource.
          schema:
            "$ref": "#/definitions/Player"
definitions:
  Player:
    type: object
    properties:
      playerId:
        type: string
      alias:
        type: string
      displayName:
        type: string
      profilePhotoUrl:
        type: string
    required:
    - playerId
    - alias

Testing Our API

With this simple specification, we can test that our API is valid by using the swagger-codegen tool to generate documentation. On OS X, you can install the codegen tool via Homebrew.

$ brew install swagger-codegen

And generate and open HTML documentation with the following commands.

$ swagger-codegen generate -i swagger.json -l html
$ open index.html

If everything went well, you should see some basic documentation for the API in your browser.

The Player API

Where to Go From Here

This article showed a basic example describing a simple GET endpoint an a single resource. From here, you should have enough context to read through the Swagger specification yourself to design your own API.

Like this post? Subscribe via RSS or email to never miss an update.