
I am down in the quantum realm when it comes to API operations. Working at the atomic level when it comes to how we do APIs. One of my favorite ways to make fun of APIs is to use the How to Draw an Owl analogy for how we teach people to do APIs. TL;DR we leave out a lot of details when we talk about and teach people about APIs. To help me address this problem in my storytelling I am exploring how we can use common approaches to API governance to enable teams across the enterprise to do the right thing, take the right next logical step, and deliver consistent, simple, and useful APIs.
To help me work through exercise, I am using a common address resource to help me walk through all the invisible details of eventually what will be an API. I am purposefully trying to walk through each step of creating a new API resource in a way that can be automated at a mix of levels. This is an exercise I’ll explore with dealing with existing APIs, and consuming APIs, but for now I am exploring the minutia of producing what I’d consider a digital resource, using an OpenAPI–eventually looking to deliver a real API.
Start With a Workspace
I need a workspace to put this work in so that anyone can come and build on top of my resource, get involved, and understand what is happening. This workspace is created in Postman either manually or via the API, resulting in the following object.
id: 1f0df51a-8658-4ee8-a2a1-d2567dfa09a9
name: Address Workspace
type: team
description: For developing the address resource.
visibility: private-team
createdAt: '2023-01-01'
I now have an empty workspace where I can put my digital resource and manage the work that will occur around it. Providing a single place to get up to speed on what is happening, and get involved moving this resource forward.
Define API Using OpenAPI
For the purposes of our digital resource exercise we are using OpenAPI to describe the surface area of this API, but for this part one we will not be adding paths, and just working on the schema. To get started we have added just a title and description.
openapi: '3.0.0'
info:
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
# Empty Path
paths: {}
# Empty Components
components: {}
This OpenAPI validates. It is the minimal viable OAS you can produce, which is perfect for any new digital resource, because at this point we only have a title and description for our digital resource–we haven’t fleshed everything else out.
Change Management
To help us manage change we will be using semantic versioning for this digital resource, adding a version property to the OAS info object, using it to communicate each major, minor, and patch release.
openapi: '3.0.0'
info:
version: '1.0.0'
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
# Empty Path
paths: {}
# Empty Components
components: {}
We are using version 3.0 of OAS, but setting our own version for this resource to be 1.0.0, and we will work within this version for all of this release, as we iterate on our object, and eventually API.
Licensing
Next, we want to make sure we cover our legal bases by having a licensing as part of our OAS license object. We are using CC BY-SA, or a creative commons license for the copyright on the interface, which is the precedent set by the Oracle v Google copyright case.
openapi: '3.0.0'
info:
version: '1.0.0'
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
contact:
name: Kin Lane
email: [email protected]
license:
name: Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
identifier: CC BY-SA
# Empty Path
paths: {}
# Empty Components
components: {}
Our interface is separate from our implementation. Code will be covered by the Apache 2.0 license, while the interface is covered by copyright using CC BY-SA.
Use Existing Standards
Before we get to work actually defining our digital resource, let’s do our homework and see if there are any existing standards we should be adopting. Avoiding reinventing the wheel, while also ensuring widest possible adoption.
name: Schema.org Postal Code
description: Open source objects.
link: https://schema.org/postalCode
We are going to use the Schema.org Postal Code object as the blueprint for our digital resource, adopting the properties we are most interested in as a starting point for this resource.
Invite Stakeholders
Before we get started defining our digital resource let’s add any stakeholders to the conversation, ensuring that we have the name, email, and title for anyone involved with the delivery of our address object.
givenName: Kin
familyName: Lane
email: [email protected]
jobTitle: Chief Evangelist
I am just getting started, so I am the only stakeholder, but I’ll do the hard work to get more stakeholders involved and excited about my new digital resources.
Contact Information
Now we want to make sure at least one of the stakeholders is added to the OAS document as the contact, adding their name and email to the info contact object, ensuring there is always someone responsible.
openapi: '3.0.0'
info:
version: '1.0.0'
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
contact:
name: Kin Lane
email: [email protected]
# Empty Path
paths: {}
# Empty Components
components: {}
There should always be someone responsible for an API, acting as the point person. Even if the email goes to a general account, there should be a person who can be held responsible for each API.
Address Example
Let’s flesh out our digital resource by adding an example of what it will look like, providing a real world example in YAMl or JSON of what it will look like in the wild–providing as much detail as possible.
openapi: '3.0.0'
info:
version: '1.0.0'
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
# Empty Path
paths: {}
# Adding address example
components:
schemas:
Address:
type: object
example:
streetAddress: 123 Main Street
Now we are using the components schema object for OAS to begin fleshing out the JSON Schema for address object. All we’ve done so far is flesh out the name, type, and example for our address object–we will do more later.
Address Properties
Now that we have a simple example of what we want, let’s articulate this as JSON Schema properties, declaring the name and the type of the property–we can get into more detail later.
openapi: '3.0.0'
info:
version: '1.0.0'
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
# Empty Path
paths: {}
# Adding address properties
components:
schemas:
Address:
type: object
example:
streetAddress: 123 Main Street
properties:
streetAddress:
type: string
We will use these properties to validate our digital resource once it is being used, ensuring that the data being submitted or published is consistent with the contract for our schema.
Address Required
Now we want to make sure that you just can’t submit an empty address, requiring that you add something for the street address–something we can further define the limit and shape of later.
openapi: '3.0.0'
info:
version: '1.0.0'
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
# Empty Path
paths: {}
# Adding address required
components:
schemas:
Address:
type: object
example:
streetAddress: 123 Main Street
properties:
streetAddress:
type: string
required:
- streetAddress
We now have a solid example of our address, the underlying properties of the data, and a requirement that some value is present, establishing the baseline for our address object–something we can evolve as part of future iterations.
Tracking Change
It is important to track the changes occurring, breaking change down into incremental shifts to the contract, making it easy to see what is being proposed, and what is being changed to our digital resource.
- name: Created Workspace
description: Created a new workspace for resources.
from: [old]
to: [new]
- name: Created OpenAPI
description: Created the OpenAPI for the object.
from: [old]
to: [new]
- name: Added Version
description: Added version to the resource.
from: [old]
to: [new]
- name: Added License
description: Added license to the resource.
from: [old]
to: [new]
- name: Chose Standards
description: Choose to use Schema.org standard.
from: [old]
to: [new]
- name: Added Stakeholders
description: Added stakeholders to the resource.
from: [old]
to: [new]
- name: Added Contact
description: Added stakeholders to the resource.
from: [old]
to: [new]
- name: Address Example
description: Added an example of the resource.
from: [old]
to: [new]
- name: Address Properties
description: Added an example of the resource.
from: [old]
to: [new]
- name: Address Required
description: Ensure properties are required.
from: [old]
to: [new]
Keeping change modular, well-defined, and incremental provides a nice road map when you are planning, and a change log after things have been put in motion. Allowing change to be queued up, communicated around, and then implemented and automated through consensus.
Notifying Stakeholders
When changes are proposed, notifications can be sent to all stakeholders. Of course, when there are more stakeholders this would have more impact, but for now it gets the point across that we need to notify stakeholders with a summary of change.
- name: 'Change Summary'
description: A list of changes that have been made.
resource: Address
pubDate: '2023-01-01'
Now everyone involved should be notified of proposed changes and have examples and technical detail of what is being changed, keeping everyone involved and part of the conversation when it comes to the changes to the object.
Comments
With all stakeholders informed of changes, comments are open, allowing every stakeholder to log a comment on the changes being made, included in reporting and change log.
- name: 'Feature Support'
description: I support all of these changes.
resource: Address
from: [email protected]
pubDate: '2023-01-01'
Comments are a way to log feedback from all stakeholders involved in the forward motion of each digital resource, making sure every change has the required architecture decision records for the future.
Votes
One additional dimension could involve voting by stakeholders on each individual change proposal, allowing a consensus model to be applied to the forward motion of each of our digital resources.
- vote: Yes
resource: Address
change: Address Properties
by: [email protected]
pubDate: '2023-01-01'
- vote: Yes
resource: Address
change: Address Requirements
by: [email protected]
pubDate: '2023-01-01'
Votes can be the easy way to get consensus amongst stakeholders, allowing everyone to respond via message or API request to vote yes or no on each individual action, or possibly a summary of changes.
Policies
Everything we have done so far can be defined as an official policy, shaping how all digital resources get defined as human readable, but also very formal policies defined to shape business operations. Providing a series of common steps that get used to move our address object forward, but reflect activities across all API.
- name: Workspaces
description: Every resource should have its own workspace.
scope: Implementation
- name: OpenAPI
description: Every resource should have its own OpenAPI.
scope: Implementation
- name: Title
description: Every resource should have an information title.
scope: Implementation
- name: Description
description: Every resource should have an information description.
scope: Implementation
- name: Version
description: Every resource should have an information version.
scope: Implementation
- name: License
description: Every resource should have an information license.
scope: Implementation
- name: Standards
description: Every resource should use existing standards.
scope: Implementation
- name: Stakeholders
description: Every resource should have associated stakeholders.
scope: Implementation
- name: Contact
description: Every resource should have an information contact.
scope: Implementation
- name: Schema Examples
description: Every resource schema should have an example.
scope: Implementation
- name: Schema Properties
description: Every resource schema should have properties.
scope: Implementation
- name: Schema Required
description: Every resource schema should be required.
scope: Implementation
These policies are the formal business definition of what needs to happen, providing a straightforward explanation of each building block of API operations. Policies provide the human definition of what occurs, which is mapped to machine-readable Spectral rules tha automate the policy.
Rules
Rules are machine readable Spectral rules designed for specific sources of information, with the workspace and OpenAPI artifacts pulled using the Postman API. These rules are examples of what can be applied to each of the existing outputs for this work, automating whether or not each individual policy is applied or not.
- postman-workspace-exists:
policy: Workspace
points: 10
description: Ensures that a postman workspace exists.
message: The resource should have a workspace.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- postman_workspace
then: [example]
- postman-api-openapi-exists:
policy: OpenAPI
points: 10
description: Ensures that a postman API OpenAPI exists.
message: The resource should have an API OpenAPI.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- postman_workspace
then: [example]
- openapi-v3-info-title:
policy: Title
points: 10
description: Ensures that all OpenAPIs have an information object title.
message: The info object should have a title.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-info-description:
policy: Description
points: 8
description: Ensures that all OpenAPIs have an information object description.
message: The info object should have a description.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-info-version:
policy: Version
points: 10
description: Ensures that all OpenAPIs have an information object version.
message: The info object should have a version.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-info-license:
policy: License
points: 10
description: Ensures that all OpenAPIs have an information object license.
message: The info object should have a license.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-info-contact:
policy: Contact
points: 10
description: Ensures that all OpenAPIs have an information object contact.
message: The info object should have a contact.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-schema-examples:
policy: Schema Examples
points: 10
description: Ensures that every schema has an example.
message: Each schema object needs an example.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-schema-properties:
policy: Schema Properties
points: 10
description: Ensures that every schema has properties.
message: Each schema object needs properties.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
- openapi-v3-schema-required:
policy: Schema Required
points: 5
description: Ensures that every schema has required properties.
message: Each schema object needs a required property.
given: "$.example"
severity: info
recommended: true
type: style
formats:
- oas3
then: [example]
This is an increasingly common way of applying a variety of rules against OpenAPI. The only unique thing here is I pull the OpenAPI from the Postman API, as well as beginning to lint workspace artifacts. With this approach I am looking to expand the boundaries of how we apply rules across API operations.
Outcomes
Augmenting policies and rules with real world outcomes to help incentivize the application of rules and policies. A policy is the formal business description, a rule is the machine readable automated portion, and outcomes are about linking the application of these policies to real world outcomes that stakeholders will care about.
- name: Easy Discovery
description: A workspace ensures that the work behind every digital
scope: Implementation
- name: Contract
description: Each digital resource possesses a machine readable contract.
scope: Implementation
- name: Simple Name
description: The title of each resource is clear and easy to understand.
scope: Implementation
- name: Adequate Description
description: A digital resource has an adequate description of what it does.
scope: Implementation
- name: Managing Change
description: Each resource is versioned to manage change.
scope: Implementation
- name: Managing Legal
description: A license is properly applied to each individual object.
scope: Implementation
- name: Person to Contact
description: There is some to contact about each individual resource.
scope: Implementation
- name: Consistency with Standards
description: Utilizing standards make the digital resource easier to use.
scope: Implementation
- name: Bring in Stakeholders
description: Make sure you have multiple stakeholders involved in things.
scope: Implementation
- name: Someone Home
description: There is someone to contact when it comes to needing help.
scope: Implementation
- name: Someone Home
description: There is someone to contact when it comes to needing help.
scope: Implementation
- name: Schema Examples Help
description: Examples for each schema help demonstrate what is possible.
scope: Implementation
- name: Validate with Schema Properties
description: The JSON Schema properties allow each resource to be validated.
scope: Implementation
- name: Required Properties
description: Makes sure digital resources contain the data necessary.
scope: Implementation
These outcomes are meant to augment policies and rules with meaningful outcomes that people care about. Adding a property to a YAML or JSON document doesn’t get people motivated, but linking it to real-world outcomes that impact people during their regular work can have different results.
Components
Now I am looking to flip policies, rules, and outcomes on their head and see if I can use rules to nudge and enable stakeholders to do the right thing in the moment. I am looking to augment policies and the machine readable rules that automate them with reusable components that can be used to enable stakeholders at each step along the way.
- workspace:
policy: Workspace
name: Workspace
description: A workspace component.
component:
name: Workspace
type: team
description: For developing the address resource.
visibility: private-team
createdAt: '2023-01-01'
- api-openapi:
policy: OpenAPI
name: OpenAPI
description: A simple OAS component.
component:
openapi: '3.0.0'
info:
title: 'Address'
description: 'This is for defining an address object for storing the details of specific locations.'
paths: {}
components: {}
- openapi-info-title:
policy: Title
description: An example title.
component:
title: 'Title'
- openapi-v3-info-description:
policy: Description
description: Ensures that all OpenAPIs have an information object description.
component:
description: 'A description'
- openapi-v3-info-version:
policy: Version
description: Ensures that all OpenAPIs have an information object version.
component:
version: '1.0.0'
- openapi-v3-info-license:
policy: License
description: Ensures that all OpenAPIs have an information object license.
component:
license:
name: Apache 2.0
identifier: Apache-2.0
- openapi-v3-info-contact:
policy: Contact
description: Ensures that all OpenAPIs have an information object contact.
component:
contact:
name: Kin Lane
email: [email protected]
- openapi-v3-schema-examples:
policy: Schema Examples
description: Ensures that every schema has an example.
component:
example:
streetAddress: 123 Main Street
- openapi-v3-schema-properties:
policy: Schema Properties
description: Ensures that every schema has properties.
component:
properties:
streetAddress:
type: string
- openapi-v3-schema-required:
policy: Schema Required
description: Ensures that every schema has required properties.
component:
required:
- streetAddress
I am looking to come full circle with these components. I am looking to understand how we can use policies and rules to not govern stakeholders throughout their journey, but enable them. When someone is staring at the beginnings of an OpenAPI contract, wondering what they need to do next, there is a nudge, with a ready-to-go reusable component available to put to work.
Turning Governance into Enablement
This exercise was about connecting all of the dots when it comes to delivering an entirely new API, but slowing down and being very deliberate about each step. So much so, I barely even got the schema for our digital resource defined. In part two I am looking to further flesh out this object and then define some simple access using an HTTP API. Similar to this, I am looking to step through the addition of each element of my digital resource, and carefully craft a policy that guides, a machine readable rule that automates, and a reusable component that enables–all leading to logical business outcomes.
Gamifying Instead of Governance
If you notice, each of the Spectral rules have a point property. When a rule is applied against our OpenAPI artifact the points accumulate and remain a property of our object. I am exploring ways in which rules can be applied to our APIs, as well as the operations around them. I am also looking to iterate and evolve upon rules and other reusable components in the same way I am governing my address object. Spectral rules should have points. Reusable components should have points. All of these building blocks of our API operations should be improved upon and gamify the evolution of building blocks.
A Platform-Level Artifact
I am not satisfied with beginning this journey with OpenAPI. It should be a higher level abstract artifact like APIs.json or something. The JSON Schema should be developed independently of OpenAPI, or partially AsyncAPI. A workspace could contain multiple APIs, and there will be multiple collections eventually–once I get to mocking, documentation, and testing for my API. Regardless, I am still learning as part of this exercise. I am pushing the boundaries of governance here, flipping governance on its head and making it more about nudging and enablement of everyone involved. To be able to make this intelligent and relevant to what teams are doing, it will have to have a platform or at least program level artifact to keep track of everything.
Iterate Upon My Address Resource
Next I will add more properties to our address object, and begin iterating upon the API paths. I am looking to keep with my How to Draw an Owl analogy and show my homework. Developing policies and rules along the way that help automate and translate each step into business outcomes. I am looking to translate each step in how to do an API into guidance and enablement. I don’t want all of these policies and rules to be seen as governance. I don’t want these policies and rules to be seen as a checklist of what has to happen. I want policies and rules to be seen as helpful guidance along the way, delivered when they are needed. I want this guidance to be right there under the fingertips of anyone involved with moving an API forward. To do this we’ll need an overarching program lifecycle and artifacts, for our standards, as well as each individual API we are delivering.