Linting OpenAPI specs using Spectral
mnlth
Posted on May 9, 2021
Introduction
This post details on linting swagger specification using spectral. When it comes to following standards, its always conversational and prone to deviations with human aspect. How good would it be to automate the verification of standards.
Its such a relief to hear about a positive move towards lint option on json and yaml variant of API specs. Yes, Spectral provides lint'n options to json or yaml objects. Unlike regular linters which checks for syntax, spectral provides an option to create your own ruleset to apply on the openapi swagger specification file.
Spectral comes with built-in functions with provision to create custom functions. These custom functions can perform pattern checks, parameter checks, provided keys in an object and many more.
Usage
There are a few options available for installation and usage based on requirements. Lets look into these
- node
npm install -g @stoplight/spectral
- yarn
yarn global add @stoplight/spectral
- run as binaries
curl -L
https://raw.githack.com/stoplightio/spectral/master/scripts/install.sh | sh
- docker
Running docker image locally requires file to be copied on to volume mount
docker run --rm -it -v $(pwd):/tmp stoplight/spectral lint "/tmp/file.yaml"
If you want to run docker from CI, use docker command
docker run --rm -it stoplight/spectral lint "${url}"
Example:
Let me show simple usage of running docker locally on employee-openapi-spec.yaml
using the command
docker run --rm -it -v $(pwd):/tmp stoplight/spectral lint "/tmp/employee-openapi-spec.yaml
openapi: 3.0.1
info:
title: Employees API Spec
description: Working with employee details
version: v1
servers:
- url: http://localhost:8080/employees
description: The employee api
tags:
- name: employee details api spec
paths:
/api/v1/employees:
summary: Employees
description: API to work with employee details
get:
tags:
- employees
summary: Get list of employees
description: Retrieve the list of employees and their details
operationId: getEmployees
responses:
"200":
description: request to get list of employees
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeResponse'
And the output looks like this
OpenAPI 3.x detected
/tmp/employee-openapi-spec.yaml
2:6 warning info-contact Info object should contain `contact` object.
17:9 warning operation-tag-defined Operation tags should be defined in global tags.
ā 2 problems (0 errors, 2 warnings, 0 infos, 0 hints)
Features
With the ability to add linter enables to detect issues with API early on, as early as design phase. Isn't this an amazing benefit to shift left on design issues and save time for more precious work later.
Spectral has three key building blocks:
Rulesets - act as a container for rules and functions.
Rules - filters the object to a set of target values and specifies the function that is used to evaluate these values.
Functions - accept a value and return any issues with its value.
As mentioned earlier, spectral comes with basic set of functions and a predefined set of style guides for openapi specs. Rules are created using one or more of these basic in-built functions to add onto the style guides. These additional ones could be organisational guardrails which can be centrally managed and enforced onto all the APIs being designed. These could be anything from
HTTP Basic is not allowed at this company
to checking
Are all operations secured with a security schema
Working with Rulesets
Let's dive into exploring rulesets and working with custom functions. Since spectral supports linting of json and yaml objects, rulesets can also be in either of the formats. Often the ruleset filename goes like .spectral.yaml
which consists of two parts, rules and functions.
In-built Spectral "oas" ruleset, OAS being shorthand for the OpenAPI Specification. In the above example, we saw a warning on info-contact
. This is one of the default ruleset of oas.
Creating any custom rules requires .spectral.yaml
file in current working directory. Here's how a simple custom rule looks like.
Simple ruleset example
rules:
my-rule-one:
description: Tags must have a description.
given: $.tags[*]
severity: error
then:
field: description
function: truthy
The rule is applied on the json element tags
defined under given
and the function is truthy
with reporting severity as error
. This means, if any of the specification tags
doesn't contain description
, linter will throw error.
Spectral cli command to apply the rule:
spectral lint employee-openapi-spec.yaml
. This command will now use custom rules file instead of default spectral ruleset.
Extending ruleset
extends: spectral:oas
Just by adding extends statement to the spec, you can import other default rulesets. So when the above created custom rule combined with default ruleset looks like:
extends: spectral:oas
rules:
my-rule-one:
description: Tags must have a description.
given: $.tags[*]
severity: error
then:
field: description
function: truthy
This is essentially to instruct spectral to apply default rules plus the additional custom rule.
Custom ruleset
extends: spectral:oas
rules:
operation-2xx-response: warn
Change the severity - update the default severity of rule by overwriting it. Different severity levels that can be used are error
, warn
, info
, hint
, and off
.
Turn off a rule
extends: [[spectral:oas, all]]
rules:
my-rule-one: off
Here all the default spectral rules are enabled and only custom rule my-rule-one
is disabled.
Turn on a rule
extends: [[spectral:oas, off]]
rules:
my-rule-one: true
This is quite opposite to disabling a rule. Default rules are all disabled using off
flag and only my-rule-one
is enabled.
Conclusion
There are a few more options to customise the rules to cover most of the organisational requirements. Also, it is a good start to see a working lint option available for swagger which removes the overhead of manually verifying and controlling the common design pattern for APIs. I'm pretty impressed and suggest trying this to see the benefit of automating early design flaw detection. Hope you find this useful.
References
Posted on May 9, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.