Part 2 - Continuous Integration
This is part two in a series of posts, showing how Spectral can help power a chunk of your API Governance program, by automating parts of the API Design Review that a human doesn’t need to concern themself with. Check out part one here.
In Part One we looked at creating your first automated API Style Guide with OpenAPI and a Spectral Ruleset. That ruleset just lived on your local computer, so what could be done to get it into other environments, be that other API designers/developers, or continuous integration?
- via Git
- via URLs
- via NPM
This article will go through all of these options, showing the use cases they are useful for, which will hopefully help you get an idea of how flexible Spectral is for any workflows.
Distributing Style Guides via Git - Single API
The most simple use-case is one API, in one repo. If this is the case, you could commit the Spectral ruleset containing your style guide to that Git repo, and run continuous integration on it there.
To start this off, plop the
.spectral.yaml from Part One (source code here) into the root of your project, then anyone working on that repo as a Stoplight Project (either locally with Stoplight Studio Desktop, or online via Stoplight Platform) will see the Spectral warnings and errors as they work on the OpenAPI documents.
Then, the continuous integration setup is a case of running the CLI on pull requests. This article will cover using CircleCI, but the concepts are very similar regardless of what CI system you use.
Head over to CircleCI, and set up a new project, which will probably be the gitHub repo that your API source code (and OpenAPI documents) live in.
The interface will ask for a config file, which should look something like this:
# .circleci/config.yml version: 2.1 jobs: lint: docker: - image: cimg/node:16.8 steps: # Checkout the code as the first step. - checkout # Create a folder for results to live in - run: "[ -d lint-results ] || mkdir lint-results" - run: name: Lint API Style Guide command: npx @stoplight/spectral-cli lint reference/Some-API.yaml -f junit -o lint-results/junit.xml - store_test_results: path: lint-results workflows: sample: jobs: - lint
For those not familiar with CircleCI, take a look at the CircleCI Config documentation to get ramped up, or we can just focus on the
command: part which is the meat of this setup.
Let’s zoom in on that section.
command: npx @stoplight/spectral-cli lint reference/Some-API.yaml -f junit -o lint-results/junit.xml
To start off with,
npx is a really handy command that lets you run commands from NPM (Node Package Manager) modules without needing to explicitly install them, or maintain a
package.json in your repo. The command being used here is basically the equivalent of running
npm install @stoplight/spectral-cli, then running
spectral lint reference/Some-API.yaml.
reference/Some-API.yaml can be updated to whatever your OpenAPI document is (if it’s split across multiple files then point Spectral at the main document and it will follow $ref’s).
Then we’ve got two more arguments being passed:
-f to pick the output format, and
-o to say where the output should be stored in the filesystem instead of being output to the console. jUnit is an XML-based format first born from Java testing tools, which is commonly used for storing test results. It’s become a bit of a pseudo-standard for continous integrations test results, and CircleCI will take this format to display visual test results. This means you don’t need to dig through thousands of lines of CLI output in order to see where problems are.
Anyone looking at the build results can quickly see that mistakes were made according to the style guide, and click on the failures to see a bit more about what the problem is.
This is the most simple setup, but let’s try some more advanced stuff.
Distributing Style Guides via Git - Monorepo
If there are multiple APIs in the one main API, you could do a few different things. You could have a different command for each API (which is a bit of a fudge), or you could use a convention of having the same directory name for the directory the OpenAPI files live in.
Let’s say each API has its own folder in the monorepo.
projects --| some-api ----| reference ------| openapi.yaml ----| src ------| app.js
If the name of that folder is consistent, then you could use wildcard (glob) syntax to find multiple OpenAPI documents:
npx @stoplight/spectral-cli lint **/reference/openapi.yaml
This will run Spectral on all of the APIs using the same style guide ruleset. This might feel a little heavy-handed, but if you need to avoid some rules for some APIs, you can use a Spectral feature called Overrides to turn them off, change the severity, etc.
Distribute via URL for Multiple Repositories
Seeing as the API Style Guide we’ve created so far is a YAML file, we can pop that up online anywhere and people can point to it. This could be hosted in Amazon S3, your own website, wherever you like, or you can point to a public GitHub repo.
Then each git repository that contains an API has two options for setting this up. They could copy and paste that CircleCI setup and point to the URL of that ruleset like so:
# .circleci/config.yml version: 2.1 jobs: lint: docker: - image: cimg/node:16.8 steps: # Checkout the code as the first step. - checkout # Create a folder for results to live in - run: "[ -d lint-results ] || mkdir lint-results" - run: name: Lint API Style Guide command: npx @stoplight/spectral-cli lint reference/Some-API.yaml -r
https://raw.githubusercontent.com/philsturgeon/spectral-governance-p2/main/.spectral.yaml -f junit -o lint-results/junit.xml - store_test_results: path: lint-results workflows: sample: jobs: - lint
Alternatively, the API developers could set their own Spectral ruleset which extends that, which will give them a bit more power to customize things if they need to. To try this out, create a new
.spectral.yaml in the root of the API repo with the following content:
# .spectral.yaml extends:
This way if the API developers ever need to disable a rule with skips or overrides, they can do that on their end without having to mess with the CI setup. This also means the governance team can occasionally review the spectral configs to keep an eye on who is skipping and overriding what in their rulesets, or who has come up with new and interesting rules that could be elevated to the main style guide.
Distribute via NPM
As with all technical choices, there are pros and cons. Distributing via a URL is relatively simple to do, but when it’s just YAML there’s no way to also share your custom functions. If a ruleset becomes advanced enough it starts using custom functions, distributing via NPM might be a more appropriate option.
As this is a power user feature we’ll leave this one to the documentation, and you can try using these more common use-cases first to get an idea of how things all work.
Try one of the above approaches out and see what works for you. If you can get Spectral running in CI, get it hooked up to pull requests, and see if you can make it fail when Spectral notices style guide errors being committed to your repository. If you do this, the APIs at your organization should only get better over time.
That is unless you notice some new rules that need adding, but how can you do that without breaking the build for all the API Developers? In the next part of this series, we'll look at some options for organizing and versioning your rulesets to avoid causing undue pain for your API Developers.
For more resources on style guide creation and implementation, check out our style guide best practices, or feel free to tweet at me @philsturgeon.