Skip to content

Instantly share code, notes, and snippets.

@elmiko
Last active April 30, 2018 07:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elmiko/7d97fef591887aa0c594c3dafad83442 to your computer and use it in GitHub Desktop.
Save elmiko/7d97fef591887aa0c594c3dafad83442 to your computer and use it in GitHub Desktop.
OpenAPI usage for capturing schemas and microversions in OpenStack

OpenAPI usage for capturing schemas with microversions in OpenStack

Abstract

This document proposes a usage of the OpenAPI specification as a machine readable for format for conveying OpenStack project APIs, including historical microversion data.

Background

The OpenStack community has approached the topic of machine readable API schemas and formats for at least as long as the API-SIG (formerly API-WG) has existed. These efforts have included the usage of WADL as a format for documentation, proposals for OpenAPI (formerly Swagger), and currently the os-api-ref project. While WADL was used at one time, this period was before the widespread adoption of microversions.

As microversions have become more prominent throughout the OpenStack API ecosystem, the requirements of an API documentation format have narrowed significantly. Currently there is a desire from the community to create machine readable API schemas for use in tool and SDK development as well as documentation. While OpenAPI has been considered and rejected in the past for the inability to easily integrate microversions, there exists a middle ground solution that will aid the development community and move the state of the art forward for OpenStack API schema documentation.

Solution

The OpenAPI specification (both version 2.0 and 3.x) include an extension mechanism for adding arbitrary data to a schema document. This extension field mechanism can be used to hold information about historical microversion changes. By standardizing the usage of a named x-openstack-microversions extension field on the Paths Object and the Path Item Object historical information about URIs and payload changes can be captured.

The base OpenAPI schema for any project should represent the current latest version of an API. This may be the tip of master development if pulled directory from a repository, or a tagged version if pulled from an official release. Any microversion information will be captured through the use of the x-openstack-microversions field.

An alternative approach to the base OpenAPI schema being at master is to have the base schema hold the minimum viable version of the API. More recent changes would be expressed using the same mechanism as below by defining later version (ie increasing in version number) in the extension points. In this manner, the base API would always be assured to work against the minimum released version of OpenStack.

For full URI changes, the x-openstack-microversion field of a Paths Object should be filled with a key-value store object containing the microversion tags as keys and a Paths Object as the value for each key. This usage would apply to scenarios where a URI was removed or changed names in historical versions of the API.

Example 1. Paths Object usage, changing a URI name

paths: 
  /pets: 
    get: 
      description: "Returns all pets from the system that the user has access to"
      operationId: "findPets"
      produces: 
        - "application/json"
      responses: 
        "200":
          description: "pet response"
          schema: 
            type: "array"
            items: 
              $ref: "#/definitions/Pet"
        default: 
          description: "unexpected error"
          schema: 
            $ref: "#/definitions/ErrorModel"
  x-openstack-microversions:
    0.9.9:
      /pets:
        get:
          default:
            schema:
              $ref: “#/definitions/NotFoundErrorModel”
      /allpets:
        get: 
          description: "Returns all pets from the system that the user has access to"
          operationId: "findPets"
          produces: 
            - "application/json"
          responses: 
            "200":
              description: "pet response"
              schema: 
                type: "array"
                items: 
                  $ref: "#/definitions/Pet"
            default: 
              description: "unexpected error"
              schema: 
                $ref: "#/definitions/ErrorModel"

For changes within a URI, the x-openstack-microversion field of a Path Item Object should be filled with a key-value store object containing the microversion tags as keys and a Path Item Object as the value for each key. This usage would apply to scenarios where a method, parameter, or payload has changed within a URI for historical versions of the API.

Example 2. Path Item Object usage, changing a parameter name

paths: 
  /pets: 
    get: 
      description: "Returns all pets from the system that the user has access to"
      operationId: "findPets"
      produces: 
        - "application/json"
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          type: integer
          format: int32
      responses: 
        "200":
          description: "pet response"
          schema: 
            type: "array"
            items: 
              $ref: "#/definitions/Pet"
        default: 
          description: "unexpected error"
          schema: 
            $ref: "#/definitions/ErrorModel"
  x-openstack-microversions:
    0.9.9:
      /pets:
        get: 
          description: "Returns all pets from the system that the user has access to"
          operationId: "findPets"
          produces: 
            - "application/json"
          responses: 
            "200":
              description: "pet response"
              schema: 
                type: "array"
                items: 
                  $ref: "#/definitions/Pet"
            default: 
              description: "unexpected error"
              schema: 
                $ref: "#/definitions/ErrorModel"

While this solution limits the usage of the x-openstack-microversions field to the Paths Object and Path Item Object initially, it could easily be expanded for use in other OpenAPI objects as required or to more efficiently convey data. Additionally, the limitation of object scope is fully compatible with versions 2.0 and 3.x of the OpenAPI schema.

Limitations

While this approach solves the problem of carrying the historical microversion data, it does pose a challenge to tool and SDK developers. Currently, the available automation tools like Swagger Codegen would not necessarily do anything specific with the x-openstack-microversions fields. This means that the community would be responsible for creating and maintaining any automation tooling that might utilize these fields. Alternatively efforts to improve existing automation tooling could also be employed.

Alternatives

OpenAPI schema file per version

A simple alternative to adding extension points inside the schema is to generate a schema file for each microversion. This would result in a collection of files with names that reflect the different versions (eg openapi-v1.0.0.json, openapi-v1.1.0.json). Although this methodology would require duplicating parts of the API schema across several files, it would eliminate the need for an extension and thus specialized tooling as well. This methodology also has the feature of being easily identifiable by a newcomer to the project or API.

@gildub
Copy link

gildub commented Apr 13, 2018

Thank you for sharing such hard topic as API models can be as they are very abstract.

Maybe we could shed some light to the Background section about the 2 approaches with API automation:

  • RESTful API Description Languages [1], which OpenAPI is part of among others
  • HATEOAS [2]

Also, without going into any debate about what exactly is being RESTful or not, the interesting part with HATEOAS is its dynamic feature:
"... the client is given a set of entry points and the API is discovered dynamically through interaction with these endpoints."

Openstack APIs from their inception were RESTfull and have the discovery built-in although inconsistently.
So without precluding to use the OpenAPI approach which certainly is a more practical approach for now, on the long run wouldn't HATEOAS approach provide a better solution for dynamic APIs, including microversion?

[1] https://en.wikipedia.org/wiki/Overview_of_RESTful_API_Description_Languages
[2] https://en.wikipedia.org/wiki/HATEOAS

@gildub
Copy link

gildub commented Apr 30, 2018

All those discussions might turn to be unnecessary, thanks to GraphQL which solves most of the issues typically faced by RESTful applications, including OpenStack.

After digging a bit into GrapQL, I believe 'microversion', could be initially implemented using parameters but since version management is simplified by handling deprecated fields, microversion could become redundant.

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment