Using OpenAPI to Document the API Operations You Consume
Can OpenAPI be a way to catalog and consume third-party API operations?
If someone tells you the only purpose of OpenAPI is to describe your HTTP API, they're wrong. Yes, in most situations, OpenAPI is the ideal format for defining an API. However, you can also use it for other things. Let's now look at how you can use an OpenAPI definition document as a way to document all the API operations you're consuming.
This article is brought to you with the help of our supporter, Scalar.
Scalar is a suite of powerful & customizable developer tools to help you at all stages of API development. Create beautiful API Documentation in a notion-like editing experience.
I feel it's interesting how some specification formats are so open they become a good fit for a wide range of use cases. It's easy to imagine specifications like YAML or JSON being used in unexpected ways. What's not so imaginable is seeing people use more specific formats in ways that hadn't been planned by their creators.
Take OpenAPI, the standard specification for defining RESTful APIs. Its goal is to describe the structure of an API in a machine-readable format. It supports both YAML and JSON as its underlying format. Usage of YAML is recommended if what you want is human readability, while JSON is a better approach for pure machine consumption.
With OpenAPI you can define an entire API. The advantage of using an open standard is that you can translate an API description into other things. There are OpenAPI-related tools for almost all purposes. Some tools translate an OpenAPI document into an SDK that can connect directly to an API. Other tools do a similar thing but for server code. Some other tools generate documentation on the fly. The possibilities are endless.
There's however one use case that I think hasn't been widely explored yet: Using an OpenAPI definition document to describe the way you consume one or several API operations. Instead of describing one single API, you'll be defining all the operations—from one single or multiple APIs—that you're consuming. Why is this useful and interesting?
Well, a central and up-to-date API consumption configuration works like a bookmarks folder. But, unlike a bookmark, each API operation can be interpreted by software. You could use the OpenAPI document as a source of truth for all the APIs you consume. Instead of having to update all the code that consumes third-party APIs you could simply make it read the OpenAPI document and grab the details of the operation you need. You could also use the OpenAPI document as a way to onboard new team members more easily. Instead of showing them the APIs your team consumes, simply hand out the OpenAPI document where you have all the information they'd need to get started. Let's look at an example of how you can use an OpenAPI document for defining third-party consumption.
You start by defining the openapi
and info
objects. You skip the servers
object because each operation will have its own server, as you'll see next.
openapi: 3.0.0
info:
title: Third-party operations
description: My collection of third-party operations.
version: 1.0.0
Now you can define one operation on https://api-a.example.com/users
.
paths:
/users:
get:
summary: Retrieve a list of users
operationId: getUsers
responses:
'200':
description: A list of users
content:
application/json:
schema:
type: array
items:
type: object
properties:
name:
type: string
age:
type: number
email:
type: string
servers:
- url: https://api-a.example.com/
Documenting another third-party API request is as easy as creating a new path and method. Let's create a new path and method for sending messages to a third-party service located at https://api-b.example.com/messages
.
/messages:
post:
summary: Send a message to a user
operationId: sendMessage
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
email:
type: string
responses:
'202':
description: Message accepted for delivery
servers:
- url: https://api-b.example.com
I could also have created components to abstract the response from https://api-a.example.com/users
and the request body of https://api-b.example.com/messages
. However, I kept things simple for the purpose of this example.
One first challenge, which is easy to observe with this approach, is that it's impossible to document two paths with the same name but available in different services. Suppose you wanted to document a second operation for retrieving users but from a different service. If the operation is located on the same path, i.e., /users
, you won't be able to define it in the same OpenAPI document.
A second challenge is that most of the tools won't work out of the box. The tools weren't built with this use case in mind so they might not produce the results you'd want. In many cases, you'll have to adapt existing tools or even build your own. Let's see how some popular tools can use the example OpenAPI document.
SmartBear's Swagger Editor seems to be able to handle the multiple server approach really well. Both the legacy editor and the new one can interpret that I'm configuring a different server on each operation. The editor even shows a warning message identifying it correctly interpreted the operation-level server definition: "These operation-level options override the global server options."
With other tools, the results were not so great. The main issue is the lack of support for interpreting the servers
object at the operation level. Because of that, some tools think that I'm not configuring any server and won't show the correct documentation. Other tools show the correct servers but don't have the ability to let me try to make a request.
What's really powerful with this approach is the ability to generate all the code I need to consume my list of third-party API operations. I tried the OpenAPI Generator and successfully created client code in different programming languages. Depending on the programming language, the level of sophistication in configuring the servers varies. While the Ruby generator had a project-wide configuration file, with JavaScript the server information was hard-coded on the API client code itself.
Overall, I'm quite happy with this approach. Even though I can't have multiple operations with exactly the same path, the advantage of having all my third-party operations centralized outweighs the challenges. I'm wondering who else is using OpenAPI in this way and what support tool vendors would be willing to offer.
Pretty cool - another interesting use case for this could be to provide more information to monitoring tools that support monitoring third-party APIs (e.g like https://supergood.ai/ or my own https://www.bitstreamapis.com)
I do use a similar approach, also to add strong typing to the OAS. This way, I counter the "Unsafe Consumption of APIs" vulnerability.