In an OpenAPI document, the description of the API located in the info section is not mandatory. A document without that information is syntactically valid. But from an API documentation perspective, that can be an issue. So let’s create a rule that will enforce providing this information.
If you’re unfamiliar with what Spectral is and need guidance to install and run it, check my Lint APIs with Spectral post.
The following info-description
rule is intended to check there’s a description of the API in an OpenAPI document. The given
JSON path targets the description
property in the info
object, which is located at the document’s root ($
). The rule’s then
section uses the truthy
function to check that description
is present and not empty.
If we run the Spectral CLI on the following OpenAPI document, we expect to detect an info-description
problem.
openapi: '3.0.0'
info:
title: An API without description
version: '1.0'
paths: {}
Unfortunately, no problem has been detected!
> spectral lint -r miss-target.spectral.yaml no-description.openapi.yaml
No results with a severity of 'error' found!
What happened? The checks (then
) of a Spectral rule will be executed only if the given
path returns a value, which is not the case here. There’s no description property in the info object of the OpenAPI document, the $.info.description
JSON path returns nothing. So, how can we check that description
is present?
We need to target the present info object to check that description is present. And then
, we’ll apply the truthy
function of the field
“description.”
rules:
info-description:
given: $.info
then:
field: description
function: truthy
This time, the problem has been detected!
> spectral lint -r hit-target.spectral.yaml no-description.openapi.yaml
/some/path/no-description.openapi.yaml
3:6 warning info-description "info.description" property must be truthy info
✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints)
But is that enough? What if info
is not present like in the following OpenAPI sample document? Same issue as at the beginning of this post. Our info-description
rule will not be triggered so that no problem will be detected. I let you write an info
rule to ensure the info
object is present.
But, in that specific OpenAPI use case, we don’t have to worry about info
being absent. Indeed, the info
object is mandatory in an OpenAPI document, so the document above is syntactically invalid. But you may have noticed that Spectral didn’t say anything about this when testing your info
rule. It’s because we didn’t ask Spectral to do that OpenAPI syntax check. We’ll see how to do so in an upcoming post.
Linting an API contract consists in analyzing its interface to “detect bugs, stylistic errors, and suspicious constructs” (like the original linting). That can be done, for instance, with a tool called Spectral to analyze OpenAPI documents, which contain standard and machine-readable API definitions.
As explained in previous articles, API governance aims to maximize the value created by APIs in alignment with the organization’s goals and constraints. It does this by enabling and facilitating people to work together on the right APIs in the right way. How can a linter contribute or not to that vision?
A linter, like Spectral, can participate in creating APIs right, following the organization’s guidelines, but incompletely.
For instance, it’s simple to check in an OpenAPI document that:
Such simple aspects will always be right once checked with Spectral (and fixed).
If we go a bit further, it is also possible to check that:
But this will have some limits. Most of the time, it will still be up to humans to choose the correct design pattern. If the linter can detect it, it is at least possible to check it is fully used.
If a linter, such as Spectral, can more or less tell if an API has the correct look and feel, it will probably never be able to tell:
An API contract linter will never replace an API review done by human beings to ensure the API created is the right one, aligned with the organization’s goals.
An API contract linter can be used as an enforcer (a person or group that compels observance of or compliance with a law, rule, or obligation) enforcing API governance policies. Linting can be integrated into CI/CD processes to check and block the build and deployment of APIs having a contract considered invalid. But you can use it in more clever and constructive ways.
It can guide API designers if it is integrated earlier into the API design process and tools. It will help API designers make design decisions seamlessly without losing momentum. Designers will learn and follow the rules as time passes without realizing it.
It’s an enabler. It facilitates API design reviewers’ tasks. No more hours, even days, lost painfully checking that all property names of all schemas are camel-cased. They can even create more fine and custom rules to detect patterns that should be discussed during an API design review.
So, API contract linting will only take care of some parts of API governance, but what it can do is pretty interesting. It helps to create APIs almost right, sharing a similar look and feel. As a last resort, it can be the guardian before deployment, but before that, it can be a teacher, guiding API designers and facilitating the work of API design reviewers.
]]>apiResponses
, pathResponses
, and responses
properties in the early design of OpenAPI v4 is a perfect example of that concern.
Version 4 (aka. Moonwalk) of the OpenAPI Specification is in its early discussion stage. It breaks everything, and the direction taken is quite promising! This post takes its source in a discussion related to apiResponses
, pathResponses
, and responses
properties.
In OpenAPI 3 (and 2), operations’ responses can only be set at the operation level (in responses
). Though reusable responses can be created (in components.responses
), that still means you have to define, for instance, the 401
and 500
responses key and reference the predefined responses (with a $ref = '#/components/responses/<name>'
) for each operation. That’s a bit annoying.
openapi: "3.1.0"
# ...
paths:
/resources:
get:
responses:
401:
$ref: "#/components/responses/Unauthorized"
components:
responses:
Unauthorized:
description: Missing or invalid access token
# ...
In OpenAPI v4, the new design would allow defining responses at API (apiResponses
), path (pathResponses
), and operation (responses
) levels. That way, the 401 and 500 responses could be set at the API level in apiResponses
once and for all operations.
Matthew Trask was faster than me to start a discussion and point there was something wrong with apiResponse
, pathResponse
, and (just)responses
naming. “Confusing” and “verbose” were his words; I would add “inconsistent.”
As the three apiResponses
, pathResponses
, and responses
describe the same thing (responses) but at different levels (API, path, operation), I expect them to be all named responses
. It’s the context/location that tells at which level they apply (parent property name or sibling properties giving a clue about the level).
I use that “avoiding prefix as much as possible” naming strategy because:
response
” vs. “which level is this? then {level}Response
”.That is well and good, but what if we keep them named as they are?
Keeping a name such as apiResponses
vs response
implicitly defines a naming pattern that should be applied across all the specification: <location>Thing
vs. thing
.
So, if, for any reason, the apiResponses
, pathResponses
would be kept that way, for the sake of consistency, I would argue that:
responses
which is at the operation level should be renamed operationResponses
.parameterSchemas
which appears at the path and operation levels should be respectively renames pathParameterSchemas
and operationParameterSchemas
.contentSchema
properties which appears on request and response should be renamed requestContentSchema
and responseContentSchema
.So adding such a prefix may have consequences across the whole design, it’s like when throwing 💩 in a fan.
The OpenAPI Specification v4 is in the early stage, and the current naming is probably just a “typo,” or a consequence of “that looks clearer on the diagram.” Maybe it’s just because in current version 3 the property at response level already exists and is (just)responses
.
That can happen to anyone, that’s why requesting feedback, doing reviews (and defining guidelines) is important. That helps to fix simple mistakes that have lightly annoying to terrible consequences that you’ll have to live with for eons (well, until the next major version).
I love to see how what I’ve learned designing and reviewing hundreds if not thousands of API can be used in other disciplines like designing a format for instance. The concerns you have to take care of when designing APIs are not new and not only related to APIs. But API becoming first class citizen has put those concerns, such as consistency or user-experience, to the front. And now that’s a concern in everything I do.
]]>This post’s banner is an illustration from the first page of the Encyclopédie (Encyclopedia or Reasoned Dictionary of Sciences, Arts and Crafts).
I’m continuing my exploration of API governance definition. In my initial post, I attempted to define API governance and ended up with two definitions. The first helped identify the components of API governance. The second one helped me identify the values to keep in mind when establishing and conducting proper API governance:
API governance is enabling and facilitating people to work together on the right APIs, the right way to maximize the value created by APIs in alignment with the organization’s goals and constraints.
I identify four values for API governance in the definition above:
API governance initiatives must never lose sight of their fundamental objective. And it’s not defining policies, processes, institutions, and indicators to make people respect the API law. The final aim of API governance is to “maximize the value created by APIs in alignment with the organization’s goals and constraints.”
So, every policy, process, indicator, or institution must be carefully weighed regarding how it will contribute to achieving the organization’s goals while complying with its constraints.
Most API design guidelines state, “all APIs must be designed consistently.” Why? Consistent APIs are more user-friendly, meaning integration between systems is faster and costs less money. For public APIs, people will be more willing to use and buy them, so more customers.
The deeper reasons behind each policy, process, indicator, or institution must always lead to the organization’s goals and constraints. If that’s not the case, don’t bother to put them in place, they’ll only bother everyone, slow the organization and possibly cost money for nothing.
API governance is not about being the API police blocking and controlling people, making them lose their time. It’s about “enabling and facilitating people to work .. on APIs”.
API governance must have minimal overhead and must not require efforts that would prevent people from creating APIs the right way or at all.
And more than that, an API governance initiative must put, or help to put, any possible thing in place to lower the barrier to API creation—for instance, documentation (of policies and processes), tools, or automation. But API governance can go beyond “just APIs,” helping to put in place an internal API evangelization program or API design training course, for example.
But it must never do in place of people; it must never take their API ownership. It must “teach them how to fish and not bring them fish every day”: favor the spirit of an “API Center of Enablement” that will teach people how to create APIs over an “API Center of Excellence” that could be the unique API factory.
The ultimate goal of any dedicated API governance initiative should even be to disappear: the “API-enabled” people and system being fully autonomous in the end.
You rarely work alone when you create APIs and even more when you put API governance in place. Different stakeholders with diverse perspectives will be involved. Even when each has the organization’s goals and constraints in mind when defining their policies, processes, and institutions, they may go against each other. If all API stakeholders don’t collaborate to ensure that, as a whole, everything fits together and is still aligned with the organization’s goals and constraints, be ready for dire consequences.
For instance, security policies should be carefully defined to avoid as much as possible to unnecessarily crippling user experience. I remember when it was forbidden to use the DELETE HTTP method to expose API documentation to the outside world or return a meaningful error explaining how to solve the problem caused by an API call.
Without collaboration between all stakeholders, there will be no effective API governance and no effective use of APIs.
With API governance, policies have to be defined, among other things. It’s a certainty. But these rules and guidelines don’t have to be abstruse, with little explanation of how to apply or implement them. People will need some overall guidance to be sure they use those hundreds, if not more, of rules and guidelines. People will need clear explanations to fix issues when they violate those rules.
People applying policies need to understand them without effort. They will need “cross concerns recipes”: instead of just being an endless separated list of rules (design vs. security, for instance), guidelines can be a list of actionable recipes merging as many concerns as possible, like “how to design a search operation” or “how to upload a file.” Some rules can be automated and integrated into design tools or CI/CD, but their error message must be clear and informative, to help users to fix the issues.
If the user experience is a significant concern when creating API, it must also be the case when implementing API governance. Forget that, and be sure your rules will never be applied correctly if applied at all.
I think that’s a common flaw of every policy-based system to lose sight of why it is put in place. The people implementing them focus on putting policies in place, possibly institutions, processes, and indicators around them, because that’s the objective they have been given; that’s what governance is made of, after all. But with these values in mind, it may be easier to implement the right governance in the right way.
]]>This post banner is a part of the “Figurative system of human knowledge”, the structure that the Encyclopédie (Encyclopedia or Reasoned Dictionary of Sciences, Arts and Crafts) organised knowledge into.
In a previous post titled Attempting to define API governance, I described API governance as follows:
API governance is establishing and overseeing decision-making, policies, practices, processes, and institutions to enable an organization’s people to collectively achieve its goals by efficiently taking advantage of private, partner, or public APIs. It aims to align APIs with business and IT strategies, to monitor and maximize the value created from them while identifying and addressing risks and ensuring compliance with regulations.
According to that previous post and this definition, API governance relies on four main components:
API governance’s policies and common practices are repeatable and shared rules and guides which define how APIs and API-related work should be done from a wide range of perspectives. This is probably the most known part of API governance, thanks to API design guidelines. API governance is even, unfortunately, too often reduced to this aspect alone, but those policies and common practices are far more than that.
They can cover a wide range of topics impacting the creation and management of APIs across their whole lifecycle, from design (the famous API design guidelines) and security to business models and terms of service. Domain standards or regulations could dictate some of those policies and common practices. For instance, PSD2 Open Banking APIs must follow EU regulators’ requirements and may apply a format such as the Berling Group one. And some policies and common practices must also cover API governance itself. For example, it’s essential to define guidelines explaining how to create API design guidelines or how to conduct an API design review.
Institution: an organization founded for religious, educational, professional, or social purposes
The “institutions” mentioned in the API governance’s definition represent who works on APIs. These are the different sub-organizations (inside the organization putting API governance in place) that directly or indirectly work on APIs. It comprises two groups, the API governance organizational representation and the various API stakeholders.
The most known and visible group involved in API governance is the API governance organizational representation itself. It can be, for example, a dedicated API CoE (Center of Excellence or Enablement), an API guild (a group of API practitioners scattered across the organization), or both.
The second group, the API stakeholders, are all the sub-organizations (teams, services, business lines, board of directors, …) involved directly or indirectly in creating APIs. These stakeholders can be, for example:
“Processes” is how (API-related) institutions (including API stakeholders and API governance representation) do APIs and API governance. It encompasses how they will collaborate, interact, apply policies, and react to indicators evolution. It also covers how the API governance representation operates and how the policies are created and modified.
Processes may involve various institutions and be purely human-based, automated, or both. They can also be interdependent. For instance, an API review process may involve business, development, and security teams and rely on human reviews and automated linting. People may check that the API will fulfill the proper business needs, that it is implementable, easy to understand and use, and does not unduly expose sensitive operations or data. And machines may verify that the design respects the organization’s look and feel and proposes authorized security modes. If a limit, an error, or a missing element is detected in design guidelines during the creation of an API, it will trigger the guidelines revision process. The 100% automated API production deployment process could only run if the API review process is OK.
API governance indicators are used to monitor the value created directly or indirectly by APIs and their alignment with the organization’s goals and constraints. As API governance participates in that and aims to impact it, it should also be monitored to evaluate its effectiveness.
Like policies, indicators may cover a wide range of perspectives, from pure API statistics, such as the number of APIs consumed by more than one consumer, to business indicators, such as the number of new customers acquired through APIs, and governance indicators, such as the length of the review process.
So API governance is composed of policies, institutions, processes, and indicators. But described like this, it looks a bit scary, like API police or an API dictatorship. And that’s indeed a risk if governance is not conducted with the right spirit. That also looks like a massive sum of elements to put in place. Are they all needed with all features right from the start? Hopefully, no. Governance can be put in place step by step.
But these are other stories I’ll keep for later posts. In the meanwhile, don’t forget that more engaging second definition of API governance coming from my Attempting to define API governance post:
]]>API governance is enabling and facilitating people to work together on the right APIs, the right way to maximize the value created by APIs in alignment with the organization’s goals and constraints.
It hurts, but though OpenAPI 3 is five years old and has more features, many people still use its previous version: Swagger 2.0. It’s high time that this changes. Inspired by the ‘90s “Sega Does What Nintendon’t” advertising campaign, Arnaud Lauret will compare versions 2.0, 3.0, and 3.1 of the specification, demonstrating the benefits of the new features introduced by 3.x versions to create more precise, better documented, more practical, and future-proof API contract descriptions.
Why do so? Because having a better understanding of the capabilities of the new versions and thus knowing what they are missing will perhaps push users and creators to say goodbye and thank you to Swagger 2.0 and hello to OpenAPI 3.x. It may also help OpenAPI 3.x users discover features they were not aware of.
This post’s banner is a detail of the frontispiece of the “Encyclopédie ou Dictionnaire raisonné des sciences, des arts et des métiers” (Encyclopedia or Reasoned Dictionary of Sciences, Arts and Crafts) drawn by Charles-Nicolas Cochin and engraved by Bonaventure-Louis Prévost.
It’s not that easy to find a definition of API governance. My ideas on the topic were not entirely clear, so I decided to work on its definition relative to other governance. I think API governance should be seen as a direct descendant of IT governance which descends from corporate governance, which descends from governance.
Governance is managing and overseeing an organization’s control and the system for doing this. It is also the decision-making among the actors involved in a collective problem by which stable practices, social norms, customs, or institutions (an organization founded for religious, educational, professional, or social purposes) are established, reinforced, and reproduced.
Corporate governance is externally and indirectly guiding, controlling, and evaluating a company and the system for doing this. It provides the structure through which the company’s objectives, the means to achieve them, and how to monitor performance are defined. It implies balancing all organization’s stakeholders’ interests. Responsibility, accountability, ethical behavior, corporate strategy, compliance, and risk management are the main areas of governance. Other areas are, for example, environmental awareness or talent acquisition. It differs from management; the people exercising governance, the governing agents, don’t have direct control and are not part of what they govern.
Information Technology (IT) governance is a subset of corporate governance that focuses on taking advantage of IT efficiently to enable the organization to achieve its goals, to maximize the creation of value. It aims to align business and IT strategies while identifying and addressing risks, ensuring compliance with regulations, and monitoring performance.
Like any governance, API governance refers to the decision-making among the actors involved in a collective problem (creating APIs helping the organization achieve its goals), by which stable practices, processes, policies, or institutions (organizations created for educational or professional purposes) are established, reinforced, and reproduced. For example, defining security, API design or API cataloging policies, having an API design review process, or creating an API center of enablement are part of API governance. These elements aim to facilitate, guide, and standardize the creation of the right APIs in the right way to help the organization to achieve its goals (and bring order to the API chaos in the making).
Like Corporate governance, API governance is externally and indirectly guiding, controlling, and evaluating a company’s APIs and the system for doing this. API governance is not creating APIs (API product management) or managing APIs (API management). People will make and manage APIs taking advantage of the institutions and following the processes and rules defined by API governance. The resulting APIs are being evaluated with the indicators defined by API governance. Though often people directly involved in the creation of APIs participate in governance (it is even highly recommended to ensure realistic governance), API governance agents should act as if they don’t have direct control over APIs.
Like corporate governance or IT governance, API governance implies balancing all stakeholders’ interests and the company’s objectives. The primary API stakeholders are the API providers (all members of API product teams) and the present and future API consumers. But many of the organization’s stakeholders are interested in APIs, for example, the security teams, the infrastructure teams, the business line managers, and even the board members or regulators.
Like IT governance, API governance is about what should be done and how it should be done and is both driven by IT and business. It requires aligning both IT and business. It covers all aspects of APIs, from their business inception and business model definition to design, implementation, exposition, and cataloging to (API) talent management (API design skills, internal API evangelization). It covers all types of APIs, whatever their visibility, so it concerns all public, partner, and private APIs. It’s about everything that will help maximize all APIs’ value.
Now that all that is said, how to define API governance?
As a descendant of governance, corporate governance, and IT governance, and paraphrasing their definitions, API governance could be defined as follow:
API governance is establishing and overseeing decision-making, policies, practices, processes, and institutions to enable an organization’s people to collectively achieve its goals by efficiently taking advantage of private, partner, or public APIs. It aims to align APIs with business and IT strategies, to monitor and maximize the value created from them while identifying and addressing risks and ensuring compliance with regulations.
Simplifying the previous definition leads to this:
API governance is enabling and facilitating people to work together on the right APIs, the right way to maximize the value created by APIs in alignment with the organization’s goals and constraints.
I’m pretty satisfied with those definitions, although they do not provide all the tiny details of API governance. I feel the global ideas they describe are relevant and cover the topic from a high-level perspective. I’ll keep the small details for other posts.
This series aims to provide complete cross-version reference documentation about the OpenAPI Specification aggregating different sources of information. For each analyzed element, you’ll find its definition, how it evolved across the different versions of the specification, how it is used and misused and where to find more information about it. This structure may evolve with future posts.
This series’ posts are not intended to be actionable tutorials, they may be of interest to people involved in the evolution of the specification or creating tools, and also advanced OpenAPI users. Most of this content will probably be incorporated in the next version of the OpenAPI Map and be useful for more actionable series/posts about OpenAPI and Spectral.
What represents the info
property, how it is structured, is it required, and where it is located.
openapi: 3.1.0
info:
title: Dummy Bookshop
summary: A fictitious API demonstrating the OpenAPI Specification's features
version: '1.0'
description: The **Dummy Bookshop API** is a _fictitious_ API aiming to demonstrate the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)'s features.
termsOfService: https://www.dummy-book.shop/tos
contact:
name: Bookshop Support team
url: https://www.dummy-book.shop/support
email: support@dummy-book.shop
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
paths: {}
The info
property (lines 2 to 15 in the document above) contains metadata that provides an overview of an API, what can be done with it, who to contact about it, and its limitations and conditions of use. It contains:
version
properties). The OpenAPI Specification doesn’t enforce any way of versioning an API, the version just needs to be set as a string.title
) and a short and long description (summary
and description
).contact
property) to get more details or support.termsOfService
and license
properties).The info
property is an Info object and relies on two other objects; the contact
property is a Contact object, and the license
one is a License object. Those three object are extensible. All other properties are of type string
(especially the version
, see “Missing quotes around the version of the API”). Some may require a specific format (url
or email,
for example).
Property | Required | Type | Description |
---|---|---|---|
title | ✅ | string | The name of the API. |
summary | string | A short summary of the API. | |
version | ✅ | string |
The version of the API (which is distinct from the OpenAPI Specification version defined in the openapi property or the API implementation version). |
description | string |
A description of the API. Supports markdown (Commonmark) to propose rich text formatting (see "Using rich text formatting in description"). | |
termsOfService | string (url ) |
A URL to the terms of service for the API. | |
contact | Contact Object | The contact information for the exposed API. | |
contact.name | string |
The identifying name of the contact person/organization. | |
contact.url | string (url ) |
The URL pointing to the contact information. | |
contact.email | string (email ) |
The email address of the contact person/organization. | |
license | License Object | The license that is applicable to the interface contract which is described in the OpenAPI document. See What is a license for an API?) | |
license.name | ✅ | string |
The license name used for the API. |
license.identifier | string |
An SPDX license expression for the API. The identifier field is mutually exclusive of the url field. |
|
license.url | string (url ) |
A URL to the license used for the API.The url field is mutually exclusive of the identifier field. |
The info
property itself is required; an OpenAPI document will be considered invalid without it. It may be more or less complete; a minimal info
property will contain the API’s name (title
) and version (version
).
When a license
property is present, the License object must include at least a license name
, identifier
and url
are optional. According to specification and schema, when the contact
property could be empty as all properties of the Contact object are optional. Obviously, a minimal instance must contain at least one of its name
,email
, or url
properties.
Note that there’s an inconsistency between the optional status of identifier
and url
described in the specification and the official JSON Schema which makes them required (see Issue 2975, I’m waiting a confirmation before proposing a fix).
openapi: 3.1.0
info:
title: Dummy Bookshop
version: '1.0'
contact:
url: https://www.dummy-book.shop/support
license:
name: Apache 2.0
paths: {}
The identifier
and url
of the License object (license
property of the Info Object) are mutually exclusive. That means only one of them can be provided and so a License object can’t contain them both at the same time.
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
The info
property is a property of the OpenAPI object and so is located at the OpenAPI document’s root. This property and the related Info, License and Contact objects appear only once in a document.
How the info
property and its components evolved across the different versions of the specification.
The Info object hasn’t much structurally changed between version 2.0 and 3.1. Some clarifications and more-or-less non-backward compatible modifications have been made to the content of some values and some optional data have been added.
The info
property structure in version 2.0 is almost the same as in the 3.x versions minus the additions made in 3.1. Two properties, termsOfService
and description
have some “specific” behaviors that must be noted.
swagger: '2.0'
info:
title: Dummy Bookshop
version: '1.0'
description: The **Dummy Bookshop API** is a _fictitious_ API aiming to demonstrate the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)'s features.
termsOfService: https://www.dummy-book.shop/tos
contact:
name: Bookshop Support team
url: https://www.dummy-book.shop/support
email: support@dummy-book.shop
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
paths: {}
Property | Required | Type | Description |
---|---|---|---|
title | ✅ | string | The name of the API. |
version | ✅ | string |
The version of the API (which is distinct from the OpenAPI Specification version defined in the swagger property or the API implementation version). |
description | string |
A description of the API. Supports markdown (GFM) to propose rich text formatting (see "Using rich text formatting in description"). | |
termsOfService | string |
The Terms of Service for the API. | |
contact | Contact Object | The contact information for the exposed API. | |
contact.name | string |
The identifying name of the contact person/organization. | |
contact.url | string (url ) |
The URL pointing to the contact information. | |
contact.email | string (email ) |
The email address of the contact person/organization. | |
license | License Object | The license that is applicable to the interface contract which is described in the OpenAPI document. See What is a license for an API?) | |
license.name | ✅ | string |
The license name used for the API. |
license.url | string (url ) |
A URL to the license used for the API. |
Though the termsOfService
property is a string without any specific format, most parsers and tools expect its value to be a URL like in 3.x versions.
The description
property supports the GFM (Github Flavored Markdown) syntax, which differs from the one used in 3.x versions (see “Which Markdown syntax to support in description?”).
There is no structural modification in version 3.0. Still, the descriptions of two existing properties, termsOfService
and description
, have been modified, introducing more-or-less non-backward compatible changes.
openapi: 3.0.3
info:
title: Dummy Bookshop
version: '1.0'
description: The **Dummy Bookshop API** is a _fictitious_ API aiming to demonstrate the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)'s features.
termsOfService: https://www.dummy-book.shop/tos
contact:
name: Bookshop Support team
url: https://www.dummy-book.shop/support
email: support@dummy-book.shop
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
paths: {}
Property | Required | Type | Description |
---|---|---|---|
title | ✅ | string | The name of the API. |
version | ✅ | string |
The version of the API (which is distinct from the OpenAPI Specification version defined in the openapi property or the API implementation version). |
description | string |
A description of the API. Supports markdown (Commonmark) to propose rich text formatting (see "Using rich text formatting in description"). | |
termsOfService | string (url ) |
A URL to the terms of service for the API. | |
contact | Contact Object | The contact information for the exposed API. | |
contact.name | string |
The identifying name of the contact person/organization. | |
contact.url | string (url ) |
The URL pointing to the contact information. | |
contact.email | string (email ) |
The email address of the contact person/organization. | |
license | License Object | The license that is applicable to the interface contract which is described in the OpenAPI document. See What is a license for an API?) | |
license.name | ✅ | string |
The license name used for the API. |
license.url | string (url ) |
A URL to the license used for the API. |
The termsOfService
property is now explicitly a URL (Issue #661, Pull Request #255). Out of context, it is an actual non-backward compatible change, but it is not, based on the typical property usage in version 2.0.
The description
property now supports markdown using the CommonMark syntax instead of GFM syntax (Pull Request #720). This modification was introduced because the definition of GFM and its differences from the original Markdown format were unclear then. Conversely, the CommonMark specification was considered well documented, rigorously defined, and would facilitate tool creators’ work. It seems not to be the case anymore in 2022; see GFM specification, which was probably not available in 2017 and is equivalent to CommonMark specification quality. Question: At equivalent quality, could another argument in favor of such a change be to avoid using a “proprietary” format? CommonMark is a “non-proprietary” attempt to specify the Markdown syntax formally. That was a knowingly accepted non-backward compatible lossy change; markdown table support loss, among other less-used features, was considered acceptable because there was a work-around, using HTML tables, and CommonMark was supposed to evolve to support this feature (see issue #1867 and Markdown support section in Troubleshooting).
Regardless of which markdown syntax is used in description
, or any other rich text value, version 3.0 adds some precisions about markdown parsing and security: tools may ignore certain markdown features for security concerns (See issue 1078, Pull Request #1090, and Security issues with Markdown support in description in Troubleshooting)
In version 3.1, two optional properties were added; summary
was added to the Info object and identifier
was added to the License one. These are backward compatible modifications.
openapi: 3.1.0
info:
title: Dummy Bookshop
summary: A fictitious API demonstrating the OpenAPI Specification's features
version: '1.0'
description: The **Dummy Bookshop API** is a _fictitious_ API aiming to demonstrate the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)'s features.
termsOfService: https://www.dummy-book.shop/tos
contact:
name: Bookshop Support team
url: https://www.dummy-book.shop/support
email: support@dummy-book.shop
license:
name: Apache 2.0
identifier: Apache-2.0
paths: {}
Property | Required | Type | Description |
---|---|---|---|
title | ✅ | string | The name of the API. |
summary | string | A short summary of the API. | |
version | ✅ | string |
The version of the API (which is distinct from the OpenAPI Specification version defined in the openapi property or the API implementation version). |
description | string |
A description of the API. Supports markdown (Commonmark) to propose rich text formatting (see "Using rich text formatting in description"). | |
termsOfService | string (url ) |
A URL to the terms of service for the API. | |
contact | Contact Object | The contact information for the exposed API. | |
contact.name | string |
The identifying name of the contact person/organization. | |
contact.url | string (url ) |
The URL pointing to the contact information. | |
contact.email | string (email ) |
The email address of the contact person/organization. | |
license | License Object | The license that is applicable to the interface contract which is described in the OpenAPI document. See What is a license for an API?) | |
license.name | ✅ | string |
The license name used for the API. |
license.identifier | string |
An SPDX license expression for the API. The identifier field is mutually exclusive of the url field. |
|
license.url | string (url ) |
A URL to the license used for the API.The url field is mutually exclusive of the identifier field. |
The summary
property has been added to the Info object (Issue #832, Pull request #1779). It’s a short description of the API which is similar to the summary found on a path or an operation. That simplifies documentation tools work which would take the first sentence or first nth characters as a summary in previous version (See API documentation use case examples). That can also help better set the boundaries of the API (see API design use case examples).
The identifier
property has been added to the License object (Issue #1599, Pull Request #2105). It is a SPDX (Software Package Data eXchange) license expression which “provides a way for one to construct expressions that more accurately represent the licensing terms typically found in open source software source code.” The value can be an official SPDX identifier or a custom one.
This new identifier
property is optional but mutually exclusive with the url
one. No information were found in the specification, issues or pull requests explaining this mutual exclusive relationship.
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
How the info
property and its components can be used and misused.
The description
property supports markdown to propose rich text formatting (see “Which Markdown syntax to support in description?”).
description: The **Dummy Bookshop API** is a _fictitious_ API aiming to demonstrate the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)'s features.
The info
property can be used for API design, governance, documentation, and tools. Here are a few examples; some of them may deserve more complete articles.
info
property (empty paths
or empty components
) to describe the API in natural language briefly. Giving a name (title
) and crafting a short description (summary
) of an API can be an excellent start to set boundaries. The longer markdown-compatible description
can be used to list the use cases to fulfill.version
property can be used in conjunction with a semantic version (2.1,
for example) to inform about the type of changes introduced. Note that the version can be anything that fits into a string. For example, it could be an ISO8601 date (2022-07-19
).contact
information.title
and summary
properties of OpenAPI documents to generate a list of APIs.# level 1
and ## level 2,
for example) present in the description to build a menu and
various pages.description
can list the modifications a new version brings (in a # Changelog
section, for instance).contact
property.description
can be used to fill the gap in the OpenAPI Specification and add (non-machine readable) information that can’t be put elsewhere in the document, though it may be preferable to use machine-readable extensions (See Description vs extension).version
, the tool in charge of deploying an API on an API gateway may choose to update (minor change1.7
to 1.8
for example) or recreate the API (major change, 1.8
to 2.0
for example), leaving the previous version unmodified.title
as an identifier of the API (hoping there are governance controls ensuring it is unique).The usual problems, concerns, and questions encountered when using the info
property (Info, Contact, and License objects). Some of the elements evoked here may deserve more complete articles.
The info
property is described as “metadata” and could be seen as not being part of the API contract. But this property may directly or indirectly describe behavior and provide information impacting the overall API’s contract. For instance, the document(s) linked in termsOfService
could define rate limits or the description
may describe some of the API’s behavior in human-readable fashion only.
When generating an OpenAPI document from code, the version
property may contain the implementation’s version or build number instead of the interface’s contract version. The framework or library used may need some configuration tuning to ensure that the correct expected value is put in this property.
Many APIs use a major.minor
semantic versioning, so the info.version
value could be 1.0
for instance. Not putting quotes around this value will cause an error because info.version
is defined as a string and such value will be interpreted as a number by OpenAPI parsers either the document is in JSON or YAML.
A complex and long markdown description
can be a burden to write on a single line. Hopefully YAML supports multiline string values. Right after description:
add a |
followed by a new line, this allows to write multiline string values. Read more about multiline strings in YAML here.
openapi: 3.1.0
info:
title: Dummy Bookshop
version: '1.0'
description: |
The **Dummy Bookshop API** is a _fictitious_ API aiming to demonstrate the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)'s features.
# How to get an access token?
Go to the [consumer settings page](https://www.dummy-book.shop/consumer-settings) and follow the instructions.
# Concepts
The Dummy Bookshop API deals with book, authors and many other book related topics.
paths: {}
An axis of OpenAPI documents analysis (that can be done during an API review process) is to ensure the description
property doesn’t contain information that could have been described in a machine-readable way with other OpenAPI elements or information that has been already formally described elsewhere.
The description property could be used to fill the gap in the OpenAPI Specification, but the information provided are mostly human-readable only (though it could be partially machine-interpreted taking advantage of rich text features like sections). It could be preferable to take advantage of extensions (custom x- properties).
API Handyman note: A dedicated post about extensions in planned in this OpenAPI Reference series.
The use of CommonMark was introduced in 3.0 (Pull Request #720) in replacement of GFM (Github Flavored Markdown) used in previous version, see version 3.0 changelog.
According to what is said in the 3.1 specification and in the issue #972 discussion, tools should support CommonMark 0.27 and above (the latest version as of the moment of writing is 0.30).
The problem is that transitioning from GFM to CommonMark markdown syntax came with some loss, especially the (non-HTML) table support (see Issue #1867) and many people are used to table GFM syntax. The discussion about supporting table in CommonMark exists but is not yet settle even in 2022. In 2017, the table issue was known and it was decided that as CommonMark supported HTML and markdown table was possibly coming to CommonMark, it was OK to switch.
Hopefully, according to the CommonMark table discussion it seems “there are plenty of CommonMark implementations out there that offer table extensions compatible with what GitHub uses.
API Handyman note: Based on those elements, I would (I’m not speaking in the name of OAI) recommend to support the most common markdown syntax(es), especially GFM tables, and not just pure CommonMark. That way it is possible to easily deal with all versions of OpenAPI from 2.0 to 3.1 and what most users will expect regarding markdown support.
This is not an OpenAPI specific topic, any tool/format relying on markdown is subject to security issues like local file inclusion or XSS. Therefore, it is accepted and even up to the tools to ignore some normally supported markdown feature for security concerns (See Rich Text Formatting section, issue 1078 and Pull Request #1090). But, as always with security measures, a balance has to be found with user experience (completely forbidding HTML support could be a problem for instance).
In version 2.0, it was not clearly stated that termsOfService
was a URL, so some documents may contain a text value which is not a URL. Based on a search on the APIs.guru directory, it can be assumed it is quite rare, if not non-existing on public APIs, though the situation may be different on the millions on private APIs. Nevertheless, most tools parsing 2.0 documents will expect a URL and ignore other values, but maybe silently. This is not an issue anymore in 3.x documents as the specifications clearly states the expected format.
According to issue #726, the license
property describes the license (like Apache 2.0 for instance) that is applicable to the interface contract itself which is described in the OpenAPI document. It tells if one can re-implement or re-license the API, it does not apply to the implementation.
API Handyman note, I’ll need to investigate that topic, as despite what is said above, I’m not sure about what means a license for an API and even if an API can be licensed. Also does it relate to copyright (as in the Google vs Oracle API case)?
It is possible to use custom license identifier
in the License object? Yes and no. The property only expects a SPDX expression value and not an actual official SPDX identifier or a combination of those.
A pseudo-custom identifier which is a combination of existing ones can be used. The information available on the official license list will allow to parse it.
But if the identifier
is a completely custom one (which is not based on existing license identifiers), impossible to understand using the official list, how people or machine reading the document are supposed to understand that code? I wouldn’t recommend to use such an identifier unless you’re sure that people and machine using the document know what to do with it, but how to be 100% sure? In that case, it would be more secure to use a url
instead of an identifier
.
Note that the SPDX documentation can be overwhelming. On Issue #1599, silverhook shows an example of completely custom SPDX identifier:
If a license is not listed on the SPDX License List, you can still use SPDX annotation to indicate a unique license by prepending LicenseRef- to the (unique) license name. E.g. LicenseRef-My_Very_Own_Look_But_Do_Not_Touch_License-2.0 is a valid SPDX license identifier.
Some OpenAPI document may use the license object to point to their terms of service (or terms and conditions). That is not correct according to the definition (and clarification) of what is the license
property. See issue #1672.
Where to find more information about the info
property and its components.
Info object | Links | ||
---|---|---|---|
Specification | 3.1 | 3.0 | 2.0 |
JSON schema | 3.1 | 3.0 | 2.0 |
Contact object | Links | ||
Specification | 3.1 | 3.0 | 2.0 |
JSON schema | 3.1 | 3.0 | 2.0 |
License Object | Links | ||
Specification | 3.1 | 3.0 | 2.0 |
JSON schema | 3.1 | 3.0 | 2.0 |
termsOfService should be a URL | ||
---|---|---|
Components | Versions | Issues and pull requests |
|
|
|
Rich text markdown descriptions | ||
Components | Versions | Issues and pull requests |
|
|
|
Adding summary to Info object | ||
Components | Versions | Issues and pull requests |
|
|
|
Adding a license identifier | ||
Components | Versions | Issues and pull requests |
|
|
|
License and terms of service clarifications | ||
Components | Versions | Issues and pull requests |
|
|
|
The url and identifier are optional in specification and required in schema | ||
Components | Versions | Issues and pull requests |
|
|
All examples shown in this post and some others are listed below, they can be found in my openapi-samples Github repository.
Complete Info Object | Links | ||
---|---|---|---|
Complete Info, Contact and License (url property) Objects | 3.1 | ||
Complete Info, Contact and License (identifier property) Objects | 3.1 | ||
Complete Info, Contact and License Objects | 3.0 | 2.0 | |
Minimal Info Object | Links | ||
Minimal Info Object | 3.1 | 3.0 | 2.0 |
Minimal Info, Contact and License Objects | 3.1 | 3.0 | 2.0 |
Info description and markdown | Links | ||
Text only description | 3.1 | 3.0 | 2.0 |
Multiline text only description | 3.1 | 3.0 | 2.0 |
One line markdown description | 3.1 | 3.0 | 2.0 |
Multiline markdown description | 3.1 | 3.0 | 2.0 |
Text or URL termsOfService | Links | ||
Text termsOfService | 2.0 | ||
URL termsOfService | 2.0 |
This series aims to provide complete cross-version reference documentation about the OpenAPI Specification aggregating different sources of information. For each analyzed element, you’ll find its definition, how it evolved across the different versions of the specification, how it is used and misused and where to find more information about it. This structure may evolve with future posts.
This series’ posts are not intended to be actionable tutorials, they may be of interest to people involved in the evolution of the specification or creating tools, and also advanced OpenAPI users. Most of this content will probably be incorporated in the next version of the OpenAPI Map and be useful for more actionable series/posts about OpenAPI and Spectral.
What represents the openapi
property, is it required, and where it is located.
The openapi
property (line 1 in the document above) specifies the version of the OpenAPI Specification used in the document. It does not participate in the description of an API itself; it could be considered the only “OpenAPI metadata” in an OpenAPI document.
The version of the OpenAPI Specification takes advantage of semantic versioning major.minor.patch
, 3.1.0
, for instance. Therefore, the openapi
property is a string (not a number). Note that some minor non-backward compatible modifications could happen (see Changelog).
The openapi
property is required; an OpenAPI document will be considered invalid without it.
The openapi
property is defined in the OpenAPI object and located at the document’s root. It appears only once in a document.
How the openapi
property evolved across the different versions of the specification.
In version 2.0 and earlier, the specification’s version was stored in a swagger
property (at the same location) because that was the name of the specification at that time (read What is the OpenAPI Specification? to learn more about this).
The new “OpenAPI Specification” name was introduced in the 3.0 version, hence the modification of the property’s name specifying the version of the specification to openapi
.
While version 3.1 did not bring any structural change regarding the openapi property; it modified the interpretation of its value. Strict semantic versioning was used in version 3.0: a modification of the minor version (3.0.0 to 3.1.0, for instance) must be backward compatible. Version 3.1 introduces a “loose semantic versioning” where non-backward compatible minor version changes (3.1.0 to 3.2.0, for example) may be introduced if the impact is considered sufficiently low compared to the benefits.
How the openapi
property can be used and misused.
While the openapi
property has no use inside a document, it is pretty helpful for the tools and processes that take advantage of the OpenAPI Specification. By the way, if you plan to create a format (for whatever VALID reasons), I would highly recommend putting the version inside documents.
The usual problems encountered with the openapi
property.
When starting to use the OpenAPI Specification, the property and its value can be confounded with the version of the API described in the document (which is specified in info.version
). Hopefully, most of the time, parsers will raise an error, but not straightforward like “did you try to put the API’s version in the openapi
property instead of info.version
?
Be cautious with version 3.1 (and above) when working on OpenAPI-based tools because it introduces a “loose semantic versioning” where a minor version change may not be backward compatible (see Changelog). Version 3.1 introduces a few non-backward-compatible-but-with-limited-impact changes, mainly around schema definitions.
This is a concern only in version 2.0. It is recommended put quotes around the value in YAML because 2.0 would be interpreted as a number instead of a string.
Where to find more information about the openapi
property.
Banner by my partner in crime Mister Lapin.
Spectral is an open-source JSON and YAML linter created by Stoplight. Imagine ESLint or SonarQube but for JSON and YAML.
Lint, or a linter, is a static code analysis tool used to flag programming errors, bugs, stylistic errors and suspicious constructs.
Spectral checks that a JSON or YAML document respects some out-of-the-box or user-defined rules. Linting JSON or YAML documents allows ensuring different documents, possibly created by different persons are consistent with each other; that they share a similar look and feel. It makes them easier to read, and easier to maintain. Beyond styling, linting can also help avoid the use of wrong patterns.
As Spectral works on any JSON or YAML document, it can be used on formats like Kubernetes configuration file, Postman collection, Github action, JSON Schema, AsyncAPI, or OpenAPI. For instance, using Spectral, you can check that in a Github action file, all jobs have snake_case
names or that any job’s step using github-pages-deploy-action
defines a commit-message
. Linting a Postman collection, you can check that every request comes with at least an example.
Using Spectral requires defining a ruleset and then using Spectral CLI to lint (analyze) a document with it.
A Spectral ruleset can be defined in a JSON or YAML document. The following code snippet shows the content of a YAML Spectral ruleset file named rules.spectral.yaml
. It defines a title-no-api
rule that checks the name of an API (defined in an OpenAPI document) does not contain the word “API”.
rules:
# Rule's name
title-no-api:
# Rule's description
description: The title must not contain the word API
# JSON Path to target
given: $.info.title
# Control applied on the target's value
then:
function: pattern
functionOptions:
notMatch: /\b(api)\b/i
Each Spectral rule works like this one, hence “given some path then do some controls”:
given
using a JSON Path expression. The $.info.title
path targets the title
property of the info
object which is located at the root ($
) of the OpenAPI document, hence the name of the API.then
by providing a function
name and some options (functionOptions
) if required by the function. The pattern
function used here ensures that the title doesn’t match a regular expression.To install Spectral, run the following command (check the documentation for other installation methods):
npm install -g @stoplight/spectral-cli
apihandyman> npm install -g @stoplight/spectral-cli
Linting a document named openapi.yml
with the rules.spectral.yaml
created previously is done has follow:
spectral lint openapi.yaml -r rules.spectral.yaml
apihandyman> spectral lint openapi.yaml -r rules.spectral.yaml
/path/to/documents/openapi.yaml
4:10 warning title-no-api The name of the API must not contain the word API info.title
✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints)
For each problem, you get:
4:10
)as line and character numberswarning
, the default level when the rule doesn’t define it)title-no-api
)info.title
)And indeed, the document that has been linted, contains the word “API” on line 4 in info.title
as shown below:
Spectral comes with handy and ready-to-use rules and functions that will make JSON Schema, OpenAPI, and AsyncAPI documents easier. But even without them, Spectral is an awesome tool when working on APIs.
Spectral really speeds up designing APIs your organization’s way and reviewing them. Using Spectral, you won’t lose time ensuring that the name of an API does not contain the word “API,” that all of your JSON schema properties are in camelCase, that every operation returning a list proposes the right pagination parameters, or that every operation returns at least a 2XX response. It can also tell you’re using a non-evolvable data structure such as a list of string or non-user-friendly required query parameters. Triggered Spectral rules will tell you what is wrong and how to fix it.
That means API designers and API reviewers lose less time on designing APIs the right way, with the right look and feel, and spend more time on creating the right APIs. Spectral also makes APIs more user-friendly, participating in the building of a great developer experience (DX).
Spectral is a powerful tool that can be of great help to design consistent, evolvable, and user-friendly APIs easily, in the long run, and at scale. But that will happen only if you know how to fully take advantage of it.
Spectral is a powerful tool that comes with a few challenges such as mastering JSON Path, mastering the functions, creating your own functions only when needed, designing user-friendly rules, governing rules, or being sure your rules actually work. Spectral is a powerful tool that can be used in some not obvious ways to take even more advantage of it: it can output JSON and it’s also a library.
Hopefully, these are topics that will be covered in upcoming posts.
]]>