This post takes the consistency governance guidelines into practice through something called linting. If you have spent time around JS, you might know Eslint, which is the same we want to apply for the AsyncAPI documents.
Before jumping into it, I did have to split this post up into two parts to make it more digestible.
Part 1 will be the basic introduction to linting, setup, and the CI changes.
Part 2 will contain the more advanced linting rules as well as the conclusion to this setup.
Soo…
Why enforce it?
I have heard of a couple of real-world scenarios, where consistency guidelines have not been enforced, only sat. To me, this is like having laws but no police and justice system to enforce them.
Why would you go through all the trouble of setting the guidelines if you have no intention of enforcing them? Because if the users are not given an error while making the change, it is bound to not be compliant with the guidelines. Especially if you have multiple people working on the documents.
Spectral
The linting tool I will utilize is called Spectral which is an Open source tool by Stoplight. If you have not heard about Spectral, it is used to lint JSON or YAML files, meaning it supports AsyncAPI as well as other formats such as OpenAPI documents.
To understand Spectral you need to know about 3 concepts: rulesets, rules, and functions.
- Rulesets act as a container for rules and functions, this is what we will contain all the rules for ensuring the consistency guidelines are checked.
- Rules filter your object down to a set of target values and specify the function that is used to evaluate those values. Each consistency guideline will get either one or multiple rules the AsyncAPI document must comply with.
- Functions accept a value and return issues if the value is incorrect. Sometimes the built-in functions given by Spectral is not enough, as you will see in Part 2.
Getting started
To get started I want to create my own ruleset and place it within a .spectral.yml
file. The full ruleset can be found in the spectral directory.
To start with the ruleset should extend the built-in AsyncAPI ruleset (so we can leverage already existing rules), but keep them disabled as a default. This means each rule can be explicitly enabled based on what is needed.
1extends: [[spectral:asyncapi, off]]
2functions: [],
3rules:
4 ...
Now it’s time to go through each of the consistency guidelines and match each up with a Spectral rule.
Rules
Each consistency guideline is then matched against one or more Spectral rules. The majority of the rules are explained in Part 2 as it require both custom rules and functions.
Enforce API meta information
MUST contain API meta information [218].
For this, some of the built-in rules can be enabled, and set to give an error:
1rules:
2 ...
3 asyncapi-info-contact-properties: error
4 asyncapi-info-description: error
5 asyncapi-info-license-url: error
6 asyncapi-operation-description: error
7 asyncapi-parameter-description: error
8 asyncapi-operation-operationId: error
9 asyncapi-tag-description: error
Running the linting
As mentioned in the Getting Started with Governance post, I wanted the consistency guidelines to be checked locally, so you won’t have to run it through a CI system. I want to receive feedback and fail as fast as possible when making changes to the AsyncAPI documents.
I tried a couple of setups but eventually ended up with a simple package.json file.
1{
2 "scripts": {
3 "lint": "spectral lint ./documents/*.asyncapi.json --ruleset ./spectral/.spectral.yaml"
4 },
5 "dependencies": {
6 "@stoplight/spectral-cli": "^6.3.0"
7 }
8}
There are many ways you can achieve this, however, because I am gonna add other node scripts later this was the most simple for me.
Linting changes on each PR
As introduced in versioning in practice, when changes are proposed through PRs, this script needs to be run to ensure the proposed changes do not break those consistency guidelines.
This can be done by simply adapting the existing test job to also run the linter:
1...
2jobs:
3 test:
4 runs-on: ubuntu-latest
5 steps:
6 ...
7 - name: Setup Node.js
8 uses: actions/setup-node@v2
9 with:
10 node-version: 14
11 cache: 'npm'
12 - name: Install node dependencies
13 run: npm install
14 - name: Lint AsyncAPI files
15 run: npm run lint