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
- defining arrays & enumerated values in the response and query parameter
- using format such as date-time
- 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 the
data- this contains user objects.
In swagger, the array syntax for
data is basically:
Only array that return
object type require 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
/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
/users. In this
case, two is not that hard to keep in sync, but managing the sync
becomes a pain.
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
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:
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
Way to keep the swagger file DRY!
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.
Some helpful types to use when defining:
If you want to list a field can only take on certain values, use an enumerated type:
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’.
To specify a field will be a date-time field instead of just ‘string’,
format option with the string type:
The next coolest place to start specifying is query parameters. The format is similar to the definition, but there’s additional set up required.
To specify an integer as a query parameter, this is the syntax:
Parameters can be
in a query or the body. The
allows different types, such as integer, boolean, string, etc.
To specify query parameter to accept an array of items (such as a list of usernames), this is the structure:
type is array, requires option:
collectionFormat as well as
the format, in this case: csv. There are
such as tab-seprated, space-separated, pipe-separated, etc. The
items specify the expected type within the array.
To specify query parameter to accept an enumerated value, it is similar to basic query parameters:
type is string and including an
enum list of the items.
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.
The YAML file used in this article is below, copy into the swagger editor!