DEV Community

Cover image for Linting OpenAPI specs using Spectral
mnlth
mnlth

Posted on • Edited on

Linting OpenAPI specs using Spectral

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.

Crowd decision on 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
Enter fullscreen mode Exit fullscreen mode
  • yarn
    yarn global add @stoplight/spectral
Enter fullscreen mode Exit fullscreen mode
  • run as binaries
    curl -L 
https://raw.githack.com/stoplightio/spectral/master/scripts/install.sh | sh
Enter fullscreen mode Exit fullscreen mode
  • 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"
Enter fullscreen mode Exit fullscreen mode

If you want to run docker from CI, use docker command

    docker run --rm -it stoplight/spectral lint "${url}"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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'
Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Spectral documentation
OpenAPI Rules

Top comments (0)