Swagger/OpenAPI from Ground Up
I love using the Swagger/OpenAPI tool to develop APIs as I get a broader context on how to prototype the whole API quickly. Seeing the interactive documentation as I prototype the API is fantastic feedback. I get a feel for the craft of a good API.
When I have developed APIs without Swagger/OpenAPI, I would move quickly on all the easy items (i.e. return all the users), but when it came down to returning a select set of users from a query parameter array list, I would get lazy because 1) I couldn’t figure out how to do it right and 2) wasn’t motivated enough to do it right. I can fix it later, right?
Sorry, with an API, once you define an API interface, it’s there for a long time. Getting the API design right from the start makes a big difference.
This time, I want to go over key Swagger/OpenAPI formats to craft your API in the Swagger/OpenAPI editor by building an API from the ground up. This way, I can show the primitives in a more raw form have a clean slate - just enough for what you need, and I get a cheatsheet on items I use.
If you don’t know it yet, this is a follow up from my Swagger Editor: My Favorite Features article.
Items I will cover:
- minimum API description
- referencing
- defining arrays & enumerated values in the response and query parameter
- using format such as date-time
Requirements
- Introductory knowledge of Swagger/OpenAPI. My intro is here
- Swagger/OpenAPI online editor OR docker image
Basic User API
Let’s start with the absolute minimum API description in swagger:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
swagger: '2.0'
info:
title: "minimum viable swagger editor"
version: 0.0.1
description: "the least amount of setup to get swagger editor going"
paths:
/user:
get:
responses:
200:
description: "the user that runs the show on here"
schema:
type: 'object'
properties:
username:
type: 'string'
This fulfills all the basic requirements for a swagger file:
- swagger front matter
- swagger version
- info containing title, version, and description
- single endpoint
This endpoint returns a single user’s username. Which one? It’s up to the implementation, but this shows how to query for that user and the response format of the query.
Adding Additional items
In the properties section, we can start adding new properties to return with the user such as: display_name. To add that, we would add:
Return ALL the users
Let’s add another endpoint that returns all the users of the system in an array:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/users:
get:
responses:
200:
description: 'get all the users'
schema:
type: 'object'
properties:
counts:
type: integer
data:
type: 'array'
items:
type: 'object'
properties:
username:
type: 'string'
display_name:
type: 'string'
New items with this endpoint:
counts
- this is the number of items returned in thedata
fielddata
- this contains user objects.
In swagger, the array syntax for data
is basically:
Only array that return object
type require the properties
field. The properties
field do not need to exist. when the array
contained types: boolean, integer, string, etc.
This is starting to look like a solid endpoint. /user
returns a
single user. /users
returns all the users wrapped in a data field
and include the counts.
Keep it DRY
What if I want to export another field in Users? In this case, I would
have to update the properties field of /user
and /users
. In this
case, two is not that hard to keep in sync, but managing the sync
becomes a pain.
Referencing
Instead of writing the same properties description every place the same object appears anywhere in the file, use the Reference feature.
To use the reference feature, create a definitions
section in the
swagger file:
1
2
3
4
5
6
7
8
definitions:
User2:
type: object
properties:
name:
type: string
display_name:
type: string
With this definition, any section can use this with syntax: $ref:
'#/definitions/<reference name>
So, to use it, we can create an endpoint for User2 now:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/user2:
get:
responses:
200:
description: "another version using schema"
schema:
$ref: '#/definitions/User2'
/user2s:
get:
responses:
200:
description: 'get all the user2s'
schema:
type: 'object'
properties:
counts:
type: integer
data:
type: 'array'
items:
$ref: '#/definitions/User2'
Now, changes that happen in the definitions
section for User2 will
appear immediately in the /user2
and /user2s
endpoint.
Way to keep the swagger file DRY!
Model
Another bonus when using defnitions: the model section comes for free!
Scroll down to see the model definition for User2:
This gives a comprehensive definition of the model of the object in a single location. (Perfect to start building out internal storage and/or representations of the model. ;-) )
Tip: to see changes when live editing, close and open the whole model section for updates.
Additional Types
Some helpful types to use when defining:
Enumerated values
If you want to list a field can only take on certain values, use an enumerated type:
The type
here specifies what kind of enumerated items can appear in
the list and the enum
field lists those as an array. In this case,
the user2’s role can either be a ‘user’ or and ‘admin’.
Date-Time
To specify a field will be a date-time field instead of just ‘string’,
use the format
option with the string type:
Query Parameters
The next coolest place to start specifying is query parameters. The format is similar to the definition, but there’s additional set up required.
Integers
To specify an integer as a query parameter, this is the syntax:
Parameters can be in
a query or the body. The type
specifies
allows different types, such as integer, boolean, string, etc.
Arrays
To specify query parameter to accept an array of items (such as a list of usernames), this is the structure:
The type
is array, requires option: collectionFormat
as well as
the format, in this case: csv. There are
others
such as tab-seprated, space-separated, pipe-separated, etc. The
items
specify the expected type within the array.
Enum
To specify query parameter to accept an enumerated value, it is similar to basic query parameters:
The type
is string and including an enum
list of the items.
Conclusion
Swagger/OpenAPI provides a rapid prototyping tool to give a great top down view of an API’s details. With the interactive editor/documentation, it motivates me to craft the best API possible and do it right the first time.
Starting with a minimum API description, one can see how different Swagger/OpenAPI formatting works, such as referencing, array & enumerated value definition in the response & query parameter and how to specify the date-time format.
With just these items, this significatnly improves my API design. For your next API, start with Swagger/OpenAPI, you will make a beautiful API.
Appendix
The YAML file used in this article is below, copy into the swagger editor!