ARTICLE

Introducing the OpenAPI Specification

From Designing APIs with Swagger and OpenAPI by Josh Ponelat

Manning Publications
10 min readOct 28, 2020

--

This article covers:

• Informal vs Formal descriptions

• Learning about the OpenAPI specification

• Learning about YAML (as a easier-to-write JSON)

• Describing our first GET operation

_______________________________________________________

Take 37% off Designing APIs with Swagger and OpenAPI. Just enter fccponelat into the discount code box at checkout at manning.com.
_______________________________________________________

Our first taste of OpenAPI definitions

OpenAPI definitions are the heart of automating our API workflows.

They’re the slices of bread in a sandwich shop, the fruit in a breakfast buffet and the vanilla in muffins. Which is my way of saying, they’re the core of any API system.

OpenAPI definitions are a formal description of an API.

When we formally describe an API, we’re turning the idea of that API into data which we call an API Definition. That definition (as data) floats around your eco-system, fueling different parts of it. The definition can act as the basis for validation, code stubs, documentation, etc. Informal descriptions remain human readable only. Which greatly limits the amount of power that machines and system builders can wield. And we want machines to have more power, allowing them to do more heavy lifting.

PS: Machines shouldn’t have too much power, if movies have taught us anything!

But they should be able to help out a bit more.

API Definitions excite and propel me. I’ll continue to wax lyrical on the merits of API definitions. You’ve been warned!

If we were to look at where this fits in the scale of things, we could view it as such:

Figure 1. Mental model of Swagger showing where definitions fit.

In this article we’re going to convert an informal description of a single operation into a formal one. To get there, we’ll look at the informal description, get to grips with YAML and finally describe a single operation in OpenAPI.

What we’ll be touching on:

Figure 2. Where we are

The problem

In this article we want to formally describe an operation from some informal descriptions.

At the end of it, we’ll have an OpenAPI fragment that looks like this:

Listing 1. The OpenAPI fragment we’ll describe

/reviews:
get:
description: Get a list of reviews
parameters:
- name: maxRating
in: query
schema:
type: number
responses:
200:
description: A list of reviews

We won’t be working in a vacuum, we’ll base the above fragment on some informal documentation of the existing API. It looks like this:

Listing 2. Summary of GET /reviews

`GET /reviews`

Get's a list of all reviews in the FarmStall API.
The list can be filtered down by query parameters, and is paginated.
Table 1. Parameters of GET /reviews

The original docs have a few parameters, but we’re only interested in the basics. We’ll describe the single parameter maxRating. Parameters are similar enough that this gives us the ability to recognize them.

What are we going to do?

These are the issues that a formal description aims to solve. By being precise and describing as much as necessary, it allows developers/consumers to know what the API expects and how to respond, i.e. the inputs and outputs.

It also serves as a template, allowing designers of APIs to know how to describe an API without relying on their rhetoric or by having to redesign the wheel.

Example API descriptions fall on a scale of vague/useless to pedantically-precise. The latter is preferred, but sometimes too expensive or impractical. Getting to the point where developers are able to build a client without having access to the hosted API is a goal worth achieving. This means they have enough information to do this. More info is desirable and we should strive for that ideal. We need to weigh the costs, and at some point we’ll get diminishing returns in how useful our description becomes (i.e. the costs begin to outweigh the benefits).

Introducing the OpenAPI specification

Formal descriptions need a standard, or specification. The OpenAPI specification is a formal way for describing RESTful or HTTP based APIs. Which is sort of like saying it’s a template, a set of rules and constraints to show you how you could describe an API.

The trick is, if you follow the template, then software (and sometimes people ) are able to make use of your description. They’ll not only understand what you’re describing, but be able to use it as part of their system.

Sounds fun enough.

Let’s take a look at a preview of what a fragment (i.e. not complete) OpenAPI Definition looks like…

Figure 3. An example OpenAPI document, with some labels

First off… What is up with the indentation? What are the dashes… and those colons! Well, this is YAML. If you know JSON, its super simple. I promise, we’ll take a look at it in a bit

For now, I want you to take a look at the gist of an OpenAPI document/definition/description (prefer definition, its more accurate).

An OpenAPI Definition is a document(s) that conforms to the OpenAPI specification. If it breaks a rule set out by the OpenAPI specification, it’s said to be “invalid”.

A quick refresher on YAML

To conform to the OpenAPI Specification, we need a data format. We could use JSON, but when you try to write in JSON one soon learns that… well, it can be painful.

As is becoming a trend (Kubernetes, OpenAPI, Ansible, etc.), YAML is a popular alternative to JSON. Particularly for those cases, where you might be required to write pieces of it by hand because it’s a little gentler than JSON. From not having to wrap keys in quotes, to its forgiving nature regarding trailing commas.

One of YAML’s features, is its support for “flow-types”, which is what it calls the JSONlike objects {} and arrays []. With this support it becomes a full superset of JSON. Which is awesome, because all JSON documents are legal YAML documents! Booya.

JSON is kind of the standard, when it comes to Web communication. It’s the lowest common denominator of data types in various languages. It’s compact and basic enough that most programmers can grok it pretty quickly. The grammar was simple enough to fit on a business card.

Figure 4. Douglas Crawford’s JSON Grammar on a business card.

YAML originally stood for Yet-Another-Markup-Language, but they changed it to YAMLAin’t-Markup-Language. I guess they wanted a recursive acronym, although the motivation for the changed acronym, was to emphasize the data aspect, and less on the mark up of human documents.

The YAML specification is quite large, and comes in different flavors. OpenAPI focuses on the bare minimum for its needs, which is the JSON Schema of YAML version 1.2. https://yaml.org/spec/1.2/spec.html.

All this talk of schemas and specification can be daunting. OpenAPI documents are easy to work with, as they’re a prettier version of JSON.

What does it look like?

Listing 3. Aaste of YAML

SomeNumber: 1
SomeString: hello over there! ❶
IsSomething: true
# Some Comment ❷ SomeObject:
SomeKey: Some string value ❸
SomeNestedObject:
With: A nested key/value pair ( that is quite indented! ) ❹ AList:
a string
another string
SomeOldSchoolJSONObject: { one: 1, two: 2 } ❺
SomeOldSchoolJSONArray: [ "one", 'two', three ] ❺
OneTypeOfMultiLineString: | ❻
hello over there, this
is a multiline string!

❶ Strings don’t need to be wrapped in quotes, but they can be.

❷ YAML supports comments, yay!

❸ YAML uses indentation to nest object and arrays, somewhat like python uses indentation. It doesn’t matter how many spaces or tabs you use as indentation, as long as you’re consistent, YAML parsers are happy.

❹ …and you only have to be consistent within an object or array.

❺ YAML is a superset of JSON, and you can stick pieces of JSON anywhere that feels natural.

❻ YAML supports multi-line strings, although there are different variants. See: https://yaml-multiline.info/ to get more familiar. Different types to support different newline handling and trimming.

For comparison, here’s the same document but in JSON format…

Listing 4. That same taste in JSON

{
"SomeNumber": 1,
"SomeString": "hello over there!",
"IsSomething": true,
"SomeObject": {
"SomeKey": "Some string value",
"SomeNestedObject": {
"With": "A nested key/value pair"
}
},
"AList": [
"a string",
"another string"
],
"SomeOldSchoolJSONObject": {
"one": 1,
"two": 2
},
"SomeOldSchoolJSONArray": [
"one",
"two",
"three"
],
"OneTypeOfMultiLineString": "hello over there,\nthis is a multiline string!\n"
}

As we can see, it’s similar to JSON in terms of data types, but YAML supports a multitude of more advanced features, well beyond what JSON can do. Those advanced features aren’t interesting for our purposes.

If you’d like to find out more about YAML and its more flavorful features, go take a look at its homepage: https://yaml.org/.

With YAML we can write in data. It’s a powerful concept, but we’re after bigger fish. OpenAPI uses YAML as its platform to describe APIs.

And we want OpenAPI…

Describing our first Operation

What do we want to know about our operation? Enough to make requests. With our informal description, we know the critical info.

We know the Path… /reviews We know the Method… GET We know that this Operation gets a list of reviews and returns them.

Let’s write some OpenAPI!

Listing 5. The bare bones of our first operation

/reviews:                                    ❶
get: ❷
description: Gets a bunch of reviews. ❸
responses: ❹
200: ❺
description: A bunch of reviews ❻

We described an operation — to specification. Shall we break it down a bit more?

❶ The path (relative to the server)

❷ The method, in lowercase

❸ The description of the Operation, not required but often vital

❹ The responses object, holds the different responses

❺ The 200 response ( we can only describe one response per status code, although this isn’t a hinderance as we can model complex responses )

❻ The only required field in a response is a human description; we added one.

What we have is a fragment of an OpenAPI document, not a full one yet (it won’t validate). When we plug it into a full document, it’ll be perfectly legal, and we want to be legal!

At this point, we need a celebratory image. Something that captures this moment. Unfortunately, my artistic skills aren’t profound enough to match the moment. I’ll provide what I can…

Too much? Too soon? What about the parameter, you may be asking, and you’re quite right. We need to add maxRating

Extending our first Operation

Building on top of our initial OpenAPI fragment, we need to describe at least one of the possible parameters. We’ve chosen maxRating as it serves a purpose to limit the number of reviews we have based on a maximum. This allow developers and analysts to find the lower rated reviews which are often more useful for business purposes.

From our informal document we know the following:

  • We know that it’s a number
  • We know that it appears in the query string
  • We know that it’s called maxRating

Extending our first Operation

Listing 6. The maxRating query parameter

name: maxRating                                         ❶
description: Filter the reviews by the maximum rating ❷
in: query ❸
schema: ❹
type: number ❺

Okay, this is a little more involved, I dare say a little more “OpenAPI”-ish.

❶ We have the name of the parameter.

❷ We have a description of the parameter, useful for humans

❸ We have a location of the parameter, there are other locations

❹ We have a schema, this is a schema object and it can be complex

❺ Our schema is simple, we’re saying it needs to be a number.

This is another fragment, and it doesn’t stand on its own. We need to add it to our operation we described earlier (yeah, the celebration was a little too soon!).

Doing this involves copying our fragment into its rightful place…

Listing 7. Adding the maxRating query parameter

/reviews:
get:
description: Get a bunch of reviews.
parameters: ❶
- name: maxRating ❷
description: Filter the reviews by the maximum rating
in: query schema:
type: number ❸ responses:
200:
description: A bunch of reviews

Here we have our original fragment, and in it we added a parameters field, which is an array of parameters. The astute will notice the trailing dash - before the name field, indicating an array item which is an object (name, description, in and schema are fields of that object)

❶ Our parameters field

❷ The parameter object, the start of

❸ The end of the parameter object

Summary

  • The difference between a formal and informal descriptions, where the latter allows you to re-use the description in different ways.
  • Using YAML as an easier alternative to JSON, for writing and editing data.
  • How a specification helps ease the challenge of describing an API, by serving as a template.
  • How to describe a simple GET operation with OpenAPI. That includes a query parameter.

That’s all for this article.

If you want to learn more about the book, check it out on our browser-based liveBook reader here.

--

--

Manning Publications
Manning Publications

Written by Manning Publications

Follow Manning Publications on Medium for free content and exclusive discounts.

No responses yet