From a career perspective, the two things I appreciate the most are solving problems through technology and creating technical publications. The former often drives the latter: results presented in inspired-based publications are derived from a recent problem that I had successfully solved.
Along my three-decade journey, I also discovered that I enjoy making lists. Early in my career, I used quad-ruled notebooks to establish lists to work from daily.
Of course, those graphically-lined necessities have fallen aside in favor of using derived lists maintained on
For larger initiatives, simply working from a list does not provide enough details. This is often the case with ideas I have for a new publication.
In those cases, I introduce sub-items to each core list item. While it is possible to include child items at the sub-item level, I often find that I am getting into the weeds and not focusing on the broader landscape.
Once there is good coverage for each item on the list, I figure out how best to order each item. During this step, the list actually becomes an outline, where there is a sequence established to my collection of thoughts or ideas.
The resulting product is what I have ended up using for every publication I have submitted since 2015. However, the outline concept has not been limited to my technical writing. I have also employed this very same approach when building APIs.
After establishing API standards, the API-first design pattern allocates time at the beginning of the process to produce a solid API design, focusing on high-level characteristics, which include:
When developing these specifications I recommend the following lifecycle:
In the illustration above, the first step is to listen to the needs of the API and to repeat any requirements back to the product owner driving the underlying business rules. After achieving that understanding, the design phase begins by leveraging a standards-based specification (like OpenAPI). Finally, consumers of the API can preview it.
Often, the cycle does not end there, as questions and challenges arise from the preview phase. At that point, it will require additional time to share these concerns with the product owner, who will provide additional information. At that point, the cycle begins with the goal of providing a more-refined API specification.
By employing an API-first design pattern, a single-source-of-truth artifact is documented before writing a single line of code. The specification for the API will live outside the source systems that produce the actual API in a manner that can be easily cataloged and consumed by future client and service engineers.
Now, let’s get started and work through a simple use case.
After recently moving into our new home, I thought of a use case to illustrate the API-first design pattern. My idea centers around cardboard boxes used for moving one’s possessions.
Boxes are necessary before you start packing to move into a new home. If you’re like me, finding boxes that are still in good shape and for little or no cost is an ideal situation. Then, after the move is complete, finding someone to take your gently-used boxes is just as important to avoid a not-so-attractive cardboard display in the corner of your garage.
Enter the Box Finders API, where customers perform the following operations:
For simplicity, let’s assume the Box Finders API requires the following attributes:
Since I had not used the
Once
Upon selecting the Design Document option, the next step is to provide a name. For this example, I entered box-finders-spec.yaml.
At this point, an empty design document opens in Kong Insomnia:
Now, we are ready to start designing the Box Finders API.
At the top of the file, you can add some general information about the specification. I used OpenAPI version 3.0.0:
openapi: 3.0.0
info:
version: "0.0.1"
title: "Box Finders API"
Based upon the current understanding of the Box Finders API, I added the data models (also known as schema components) to the bottom of the file:
components:
schemas:
Boxes:
type: array
items:
$ref: "#/components/schemas/Box"
Box:
type: object
properties:
id:
type: number
description: Unique identifier
name:
type: string
description: Person with boxes to give away
phone:
type: string
description: Phone number of person with boxes to give away
available:
type: number
description: Number of available boxes
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
Taking this approach will keep the data side of the contract defined in one central location of the API specification.
/boxes
URIsWith the general information and schema sections in place, we can add the /boxes URIs as path items following the OpenAPI standards:
paths:
/boxes:
get:
summary: "Lists all available box collections"
responses:
"200":
description: "200 OK, all box collections"
content:
application/json:
schema:
$ref: "#/components/schemas/Boxes"
post:
summary: "Adds a new box collection"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Box"
required: true
responses:
"201":
description: "201 Created, a new box collection was added"
content:
application/json:
schema:
$ref: "#/components/schemas/Box"
In this example, I’ve added URIs to retrieve all box collections and create a new box collection under the paths section.
/boxes/{id}
URIs**
**Next, I added the ability to retrieve, edit, or delete a single box collection as additional paths, still following the OpenAPI standard:
/boxes/{id}:
parameters:
- in: path
name: id
schema:
type: number
required: true
description: "id of the box collection"
get:
summary: "Retrieves a box collection by identifier"
responses:
"200":
description: "200 OK, box collection by identifier"
content:
application/json:
schema:
$ref: "#/components/schemas/Box"
"404":
description: "404 Not Found, box collection does not exist"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
put:
summary: "Updates a box collection by identifier"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Box"
responses:
"202":
description: "202 Accepted, updated box collection"
content:
application/json:
schema:
$ref: "#/components/schemas/Box"
"404":
description: "404 Not Found, box collection does not exist"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
delete:
summary: "Deletes a box collection by identifier"
responses:
"204":
description: "204 No Content, deleted box collection"
"404":
description: "404 Not Found, box collection does not exist"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
At this point, the 0.0.1 version of the Box Finders API is complete. However, before moving forward, I felt like it was a good time to store this information inside a git-based repository. This way, the design is not limited to existing on my local machine.
The Kong Insomnia client allows integration with an existing git-based repository. I created a new repository at the following URL:
**
**
Next, I created a__personal access token__ to create read/write access to the GitHub repository. Then, I used that resulting token to set up access within Kong Insomnia for the Box Finders API specification:
At this point, I committed my changes and pushed them to GitHub. Once completed, the changes from Kong Insomnia are now available for others to pull into their own client:
Others who wish to review or contribute to the specification can use the Git Clone option from the Create menu.
With the changes noted above, Kong Insomnia shows the contents of the API:
At this point, the Box Finders API specification can be consumed by service and consumer developers without writing a single line of code.
For cases where a consumer of the Box Finders API wants to develop their application while the feature team is developing the Box Finders RESTful service, Kong Insomnia provides the entire contract for the new client to utilize:
When making a GET request to the /boxes
URI, the service will return a list of Box objects:
[
{
"id": 0,
"name": "string",
"phone": "string",
"available": 0
}
]
Using the API-first design pattern, every client or service tied to the Box Finders API can begin their development before writing a single line of code for the Box Finders service.
If you’ve
Kong Insomnia will then ask for the connection properties before attempting a deployment for the first time:
Since last year, I have been trying to live by the following mission statement, which I feel can apply to any IT professional:
“Focus your time on delivering features/functionality which extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”
**
**- J. Vester
In this article, I used Kong Insomnia to create a standardized API specification that can be fully documented, vetted, and communicated before writing any source code. This allows teams to collaborate on the design and make changes without requiring any costly service-tier updates. Clearly, this embraces my personal mission statement.
Kong Insomnia is a product that allows feature teams to remain focused on extending intellectual property value, contributing to the bottom line positively. Taking things a step further, you can easily deploy the results from Kong Insomnia to
In my personal journey, I created lists to help with my daily assignments. In most cases, those lists became outlines, which then led to designs and specifications. The API-first design pattern was a natural progression for me and is certainly a concept I appreciate and embrace.
If you are interested in the original source code for this publication, everything noted above can be found at the following link:
Have a really great day!