Enforcing consistency guidelines - part 1

Jonas Lagoni Avatar

Jonas Lagoni

·4 min read

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 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 sat 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

Next

Next up is part 2 which dives into the custom rules and functions to enforce the consistency guidelines.

Photo by Can Eğridere on Unsplash