Skip to content

Latest commit

 

History

History

openapi-manager

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

OpenAPI manager

This tool manages the OpenAPI documents (JSON files) checked into Omicron’s openapi directory, using Dropshot’s support for API traits.

Note
For more information about API traits, see RFD 479.

Currently, a subset of OpenAPI documents is managed by this tool. Eventually, all of the OpenAPI documents in Omicron will be managed by this tool; work to make that happen is ongoing.

To check whether your document is managed, run cargo xtask openapi list: it will list out all managed OpenAPI documents. If your document is not on the list, it is unmanaged.

Basic usage

The OpenAPI manager is meant to be invoked via cargo xtask openapi. Currently, three commands are provided:

  • cargo xtask openapi list: List information about currently-managed documents.

  • cargo xtask openapi check: Check that all of the managed documents are up-to-date.

  • cargo xtask openapi generate: Update and generate OpenAPI documents.

There is also a test which makes sure that all managed documents are up-to-date, and tells you to run cargo xtask openapi generate if they aren’t.

API crates

The OpenAPI manager has dependencies on a set of API crates. An API crate is a Rust library that consists of the API trait, and possibly supporting types. Each OpenAPI document should have a separate API crate.

To keep compile times down, ensure that the API crate has as few dependencies as possible. In particular, strongly avoid any dependencies on Diesel or other database logic.

The ideal set of dependencies is:

  • Common crates within omicron: omicron-common, perhaps omicron-uuid-kinds if typed UUIDs are in use, and a types crate for your service.

  • Core external crates: dropshot, serde, schemars, and uuid.

For an archetypal way to organize code, see the dependency graph in RFD 479’s Choosing between functions and traits.

Managing OpenAPI documents

For OpenAPI documents to be managed by this tool, the corresponding interfaces must be defined via API traits rather than traditional Dropshot function-based servers.

Tip
For examples within Omicron, search the repo for dropshot::api_description.

Adding new documents

If you’re defining a new service fronted by OpenAPI, first create an API crate (see API crates above).

  1. Add the API crate to the workspace’s Cargo.toml: members and default-members, and a reference in [workspace.dependencies].

  2. Following the example in RFD 479’s Trait definition, define the API trait.

In the implementation crate:

  1. Add a dependency on the API crate.

  2. Following the example in RFD 479’s API implementation, provide an implementation of the trait.

Once the API crate is defined, perform the steps in Adding the API crate to the manager below.

Converting existing documents

Existing, unmanaged documents are generated via function-based servers: a set of functions that some code combines into a Dropshot ApiDescription. (There is also likely an expectorate test which ensures that the document is up-to-date.)

The first step is to convert the function-based server into an API trait. To do so, create an API crate (see API crates above).

  1. Add the API crate to the workspace’s Cargo.toml: members and default-members, and a reference in [workspace.dependencies].

  2. Follow the instructions in RFD 479’s Converting functions to API traits for the API crate.

In the implementation crate:

  1. Continue following the instructions in RFD 479’s Converting functions to API traits for where the endpoint functions are currently defined.

  2. Find the test which currently manages the document (try searching the repo for openapi_lint::validate). If it performs any checks on the document beyond openapi_lint::validate or openapi_lint::validate_external, see Performing extra validation.

Next, perform the steps in Adding the API crate to the manager below.

Finally, remove:

  1. The test which used to manage the document. The OpenAPI manager includes a test that will automatically run in CI.

  2. The binary subcommand (typically called openapi) that generated the OpenAPI document. The test was the only practical use of this subcommand.

Adding the API crate to the manager

Once the API crate is defined, inform the OpenAPI manager of its existence. Within this directory:

  1. In Cargo.toml, add a dependency on the API crate.

  2. In src/spec.rs, add the crate to the all_apis function. (Please keep the list sorted by filename.)

To ensure everything works well, run cargo xtask openapi generate.

  • Your OpenAPI document should be generated on disk and listed in the output.

  • If you’re converting an existing API, the only changes should be the ones you might have introduced as part of the refactor. If there are significant changes, something’s gone wrong—​maybe you missed an endpoint?

Performing extra validation

By default, the OpenAPI manager does basic validation on the generated document. Some documents require extra validation steps.

It’s best to put extra validation next to the trait, within the API crate.

  1. In the API crate, add dependencies on anyhow and openapiv3.

  2. Define a function with signature fn extra_validation(openapi: &openapiv3::OpenAPI) → anyhow::Result<()> which performs the extra validation steps.

  3. In all_apis, set the extra_validation field to this function.

Design notes

The OpenAPI manager uses the new support for Dropshot API traits described in RFD 479.

With traditional function-based Dropshot servers, generating the OpenAPI document requires the implementation to be compiled. With API traits, that is no longer necessary. The OpenAPI manager leverages this to provide a fast and easy way to regenerate API documents.

This does mean that the OpenAPI manager requires the use of API traits, and that eventually all of Omicron’s Dropshot APIs should be switched over to traits.