Future-proofing your path from OpenAPI 3.0 to 3.1 and beyond!

Future-proofing your path from OpenAPI 3.0 to 3.1 and beyond!

Part 1: Component re-use and the OpenAPI road map

The most popular version of the OpenAPI Specification (OAS) as of early 2024 is OAS 3.0. While adoption of OAS 3.1 is gaining steam, users whose needs are met by 3.0 or who want to wait for 3.1 support to mature are in no hurry to update. But software ecosystems never stand still.

What can 3.0 users do now to make the update to 3.1 easier, whether it is in the near or distant future? This is the first of a series of posts addressing that question, in which you will learn:

  • the OAS road map and your possible update paths

  • schema re-use patterns that illustrate the how and why of future-proofing for 3.1

  • techniques to use in 3.0 to make it easier to quickly benefit from updating

This post provides a high-level overview. The next few posts will get into more concrete details, including a guide to actually updating your API descriptions to 3.1.

The OAS Road Map

Note: While I am very involved in the OpenAPI project, I do not speak for it! I am confident in the direction, but the details could change.

The key point of the proposed OpenAPI Specification road map are:

  • All 3.x releases from 3.2 on will be 100% compatible with 3.1

  • The 3.2+ releases will be small and incremental

  • OAS 4.0 "Moonwalk" features will be backported to 3.2+ when possible

OAS 3.1 is much bigger than 3.0, and slightly incompatible with it. While there were good reasons for this, the newly proposed road map prioritizes painless updates from 3.1, rapid implementation of 3.2+, and an incremental path to 4.0.

Three re-use challenges

These challenges come from my experience with consulting clients who are working with complex data models, or are standardizing approaches across multiple APIs. If your API has a simple, self-contained data model, you may not have seen the difficulties, or may have easily worked around them. Even then, understanding these challenges will give you more design options to support your API's growth.

Our challenges are to:

  • re-use object schemas while forbidding unknown properties

  • re-use collection schemas with different contents

  • recognize a standard component by a location-independent identifier

Let's look at these in a bit more detail before talking about the solutions in OAS 3.1 and beyond.

Object re-use and unknown properties

This challenge is most likely to show up if you are trying to align your schemas with the behavior of strictly-typed object-oriented languages. Particularly if you have a complex class hierarchy. The problem is that

  1. re-using an object schema involves using $ref with allOf, oneOf, etc.

  2. failing validation when an unexpected property is seen requires additionalProperties: false

  3. these two techniques cannot be used together[1]

components:
  schemas:
    extensibleBase:
      type: object
      properties:
        foo: {type: integer}
    sealedBase:
      # This schema fails if foo is present, because this
      # additionalProperties can't "see" the foo definition
      allOf:
      - $ref: "#/components/schemas/extensibleBase"
      additionalProperties: false

Re-using collection schemas

In strictly-typed languages, structures like collections correspond to generics (Java, C#) or templates (C++). These programming idioms have concise syntax, but in OAS 3.0's version of JSON Schema, you need to duplicate some of the generic structure for each wrapped type:

components:
  schemas:
    collection:
      type: object
      properties:
        metadata:
          $ref: "#/components/schemas/metadata"
        data:
          type: array
          items: {}   # allow anything
    thing:
      type: string
    thingCollection:
      allOf:
      - $ref: "#/components/schemas/collection"
      # Here we have to duplicate the path to the items
      properties:
        data:
          items:
            $ref: "#/components/schemas/thing"
    metadata:
      # Assume some object schema here for pagination, etc.

The three extra keywords and nesting levels here aren't too burdensome. But with a more complex container and many wrapped types, it becomes fragile to maintain.[2]

Identifying standard components

Some APIs need interoperability with industry standards.[3] For example, there are libraries for handling data that conforms to the GeoJSON standard (RFC 7946), which has standard JSON Schemas such as https://geojson.org/schema/Feature.json for a GeoJSON "feature." If you see "$ref": "https://geojson.org/schema/Feature.json" in any API, you know that you can use your GeoJSON library on that data.

OAS 3.0 describes reference URLs as locators, implying that tools should retrieve the target using the URL. However, not all tools support references to external documents. Even if they do, security policies, unreliable networks, or performance constraints can make them impractical or impossible to use. If you have to copy that GeoJSON schema somewhere else, code looking for the standard URL won't recognize the URL of the new location.

When challenges combine...

A workaround for the URL problem might be to compare the schemas instead of the references. However, experience shows that copies are often modified, for example to work around the other challenges. You might want a "strict" Feature schema that forbids unknown properties, and specializations of the Feature Collection schema with different extended or strict features. Even the most dedicated DRY programmers will resort to copy-paste(-modify) if proper re-use is too hard.

Challenges on the Road Map

So lets look at how our challenges are handled in each current or proposed release:

objectscollectionsrecognition
3.0 (July 2017)requires duplicationrequires duplicationrequires non-standard tool support
3.1 (Feb. 2021)unevaluatedProperties$dynamicAnchor + $dynamicRef, with caveatsSchemas only: $id and/or $anchor, with caveats
3.2 (Mid-2024?)unevaluatedProperties$dynamicAnchor + $dynamicRef (with clarifications?)possible backport of proposed self field + JSON Pointer
4.0 (Dec. 2024?)unevaluatedProperties$dynamicAnchor + $dynamicRefproposed self field + component name

For re-using objects while forbidding unexpected properties, there's a solid, well-supported solution in OAS 3.1.

In theory, collections are also solved in OAS 3.1. In practice, the solution depends on keywords that are often not yet implemented, even by tools claiming 3.1 support. There was a similar lag in support for discriminator with past OAS versions.

Component recognition in OAS 3.1 only works for Schema Objects, and has similar keyword support challenges. Fortunately, this is likely to be thoroughly addressed in OAS 4.0, in a way that should be possible to backport to 3.x.

What should you do in 3.0?

This post introduced the proposed road map and three re-use challenges. The next few posts will get into the concrete details of each challenge. But the basic pattern is the same for any use of 3.0 that will benefit from new features in 3.1

  1. Identify where you are working around limitations in 3.0, and why

  2. Make sure your workarounds for each limitation are consistent and recognizable (and document them as best practices within your team)

  3. If your API description is large, create an x- prefixed extension keyword for each workaround so that you (or an automated tool) can find them in the future

For these three challenges, you won't need to change anything just to move to a newer OAS 3.x version. But taking advantage of the new features will make your API descriptions more robust and maintainable.

We'll take a concrete look at how that works for the object re-use case in the next post in this series.


  1. For several years, the most common complaint about JSON Schema was this additionalProperties: false problem. The debate on how to solve it ran for more than 500 GitHub comments before we settled on unevaluatedProperties!

  2. I first saw the need for this sort of feature in Cloudflare's pre-OpenAPI documentation system, doca, which extended JSON Hyper-Schema with a limited templating keyword for their standard response envelope. This directly inspired JSON Schema draft 2019-09's $recursiveRef and $recursiveAnchor, which evolved into 2020-12's $dynamicRef and $dynamicAnchor. Cloudflare's current OAS 3.0.3 description of course lacks that capability, so you will see lots of "*-api-response-common" components that repeat the same envelope with different contents. Once they move to 3.1, they should be able to shorten their description file considerably!

  3. Special thanks to my client, the Open Geospatial Consortium, for motivating and supporting this post, and particularly for highlighting the component identification use case. As a result, I'll be using geospatial data-related examples in this and related posts.


Did you find this article valuable?

Support Modern JSON Schema and APIs by becoming a sponsor. Any amount is appreciated!