Using openapi-cli during API design: part two
Tags: api, openapi
Published: 2021-09-22 19:41:21

---
title: Using openapi-cli during API design: part two
published: true
date: 2021-03-23 04:30:57 UTC
tags: api, openapi
series: Using openapi-cli
canonical_url: https://www.aviskase.com/articles/2021/03/23/using-openapi-cli-during-api-design-part-two/
---

[Part one](https://www.aviskase.com/articles/2021/01/31/using-openapi-cli-during-api-design-part-one/) showed the basics of using `openapi-cli` for a single-definition project. Let’s see how it works for multi-definition projects.

## [<svg xmlns="http://www.w3.org/2000/svg" style="display: inline-block; vertical-align: middle;" width="1em" height="1em" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>](#multi-what)Multi-what?

By multi-definition project I mean a project with several OpenAPI description documents. For example, it can be useful if you want to keep contracts for all services in one place. Then, you can reuse common schemas between definitions.

Another use case is keeping parts of your APIs hidden from the final description document (internal and external APIs). This approach will mostly work only if separation is on path-level ([see more here](https://redoc.ly/docs/resources/hide-apis/)).

## [<svg xmlns="http://www.w3.org/2000/svg" style="display: inline-block; vertical-align: middle;" width="1em" height="1em" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>](#configuration)Configuration

In our small Stargate API example we are splitting gates and addresses APIs into two description docs ([commit](https://github.com/aviskase/openapi-cli-examples/commit/18f1bdb2de458859b93c1c99a6400567a2cb9442)). Next step is to change [configuration file](https://redoc.ly/docs/cli/configuration/#apidefinitions), so that `openapi-cli` would know that we have two definitions ([commit](https://github.com/aviskase/openapi-cli-examples/commit/47c4a4947b9827509a02c52550f036a139dccf36)).

```yaml
apiDefinitions:
  gates: openapi/gates.yaml
  addresses: openapi/addresses.yaml
```

But now we need to fix our scripts in the `package.json` so that we could work with both definitions!

## [<svg xmlns="http://www.w3.org/2000/svg" style="display: inline-block; vertical-align: middle;" width="1em" height="1em" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>](#preview)Preview

If you simply run `openapi preview-docs` as we did before, it will start server only for the first definition in config file (in our case: gates). To preview a specific definition, you need to pass a definition label from configuration file: `openapi preview-docs addresses`.

But what if we want to preview both definitions? The simple fix will be adding separate scripts to run each definition on different ports:

```json
"scripts": {
	"preview:gates": "openapi preview-docs -p 8080 gates",
	"preview:addresses": "openapi preview-docs -p 8081 addresses",
	...
}
```

Then, run both commands (either setting them to background processes or in the different terminals).

## [<svg xmlns="http://www.w3.org/2000/svg" style="display: inline-block; vertical-align: middle;" width="1em" height="1em" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>](#linting)Linting

Nothing to change here! `openapi lint` without any definition labels will check all of them.

## [<svg xmlns="http://www.w3.org/2000/svg" style="display: inline-block; vertical-align: middle;" width="1em" height="1em" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>](#bundling)Bundling

Remember how we had to use `-o dist/openapi` to properly generate bundled desciption doc for single-definition project? Now we should simply leave it as `-o dist`. This will generate `dist/gates.yaml` and `dist/addresses.yaml` based on definitions labels.

## [<svg xmlns="http://www.w3.org/2000/svg" style="display: inline-block; vertical-align: middle;" width="1em" height="1em" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>](#generating-reference-docs)Generating reference docs

To generate static reference docs we should split `npm run docs` into separate scripts to target each definition:

```json
"scripts": {
	...
	"docs:gates": "node plugins/prepareOptions.js && redoc-cli bundle dist/gates.yaml -o dist/redoc-gates.html --options .redoc.json",
	"docs:addresses": "node plugins/prepareOptions.js && redoc-cli bundle dist/addresses.yaml -o dist/redoc-addresses.html --options .redoc.json",
	"docs": "npm run docs:gates && npm run docs:addresses",
	...
}
```

There is no need to run `prepareOptions.js` twice, but I’m keeping it in case I’d want to generate only one reference doc.

* * *

The final working `package.json` is [here](https://github.com/aviskase/openapi-cli-examples/commit/48599bdfa3322e2976329e62ea2a094be4be8bd4). As you can see, we have to manually manage some building processes, but the most important pieces (linting & bundling) are quite transparent.

In the next article we’re gonna finally see juicy linting magic!