OpenLint 101
An OpenLint ruleset tells a linter where to look in a JSON or YAML document, and what must be true there. This page teaches the format through six small examples, each one tested against a real linter.
Every example lints this small OpenAPI document. Save it as openapi.yaml to follow along:
openapi: 3.1.0
info:
title: Example API
version: 1.0.0
servers:
- url: http://api.example.com
paths:
/userAccounts:
get:
summary: List every user account in the system, with paging, filtering and sorting options
responses:
"200":
description: OK
To run a ruleset, save it as .spectral.yaml and run:
npx @stoplight/spectral-cli lint openapi.yaml --ruleset .spectral.yaml
OpenLint's own command-line tool hasn't been released yet. Until it is, the Spectral CLI runs these rulesets, because OpenLint rulesets are Spectral rulesets.
1. Your first rule
A ruleset is a map of rules. Each rule has two parts: given says where to look, as a JSONPath expression, and then says what must be true there, by calling a function.
rules:
info-description:
description: Every API needs a description.
given: $.info
then:
field: description
function: truthy
This rule looks at $.info, checks its description field with the truthy function, and reports when it's missing:
openapi.yaml:2:6 warning info-description "Every API needs a description."
With no message of its own, the result uses the rule's description.
2. Severity
Each result has a severity: error, warn (the default), info or hint. Use off to switch a rule off. Errors are what usually fail a CI build.
rules:
info-description:
description: Every API needs a description.
severity: error
given: $.info
then:
field: description
function: truthy
openapi.yaml:2:6 error info-description "Every API needs a description."
3. Start from a built-in ruleset
You don't have to write every rule yourself. extends pulls in another ruleset, here the built-in OpenAPI rules, and rules then adjusts them by name: raise one to error, or turn one "off".
extends: spectral:oas
rules:
info-contact: "off"
operation-tags: error
openapi.yaml:2:6 warning info-description "Info "description" must be present and non-empty string."
openapi.yaml:9:9 warning operation-description "Operation "description" must be present and non-empty string."
openapi.yaml:9:9 warning operation-operationId "Operation must have "operationId"."
openapi.yaml:9:9 error operation-tags "Operation must have non-empty "tags" array."
Quote "off". Some YAML tools read a bare off as false.
4. Functions
The function in then decides what "must be true" means. The core functions are truthy, falsy, defined, undefined, pattern, casing, length, alphabetical, enumeration, schema, xor, or and unreferencedReusableObject. functionOptions configures them. field: "@key" checks a key instead of a value.
rules:
paths-kebab-case:
description: Path segments use kebab-case.
given: $.paths
then:
field: "@key"
function: pattern
functionOptions:
match: "^(/[a-z0-9-{}]+)+$"
operation-summary-length:
description: Summaries stay short.
given: $.paths[*][get,put,post,delete,patch]
then:
field: summary
function: length
functionOptions:
max: 80
openapi.yaml:8:17 warning paths-kebab-case "Path segments use kebab-case."
openapi.yaml:10:16 warning operation-summary-length "Summaries stay short."
5. Formats and messages
formats limits a ruleset or a rule to one kind of document, so OpenAPI rules don't fire on an AsyncAPI file. message writes the result text, with placeholders such as {{property}} and {{value}}.
formats: [oas3]
rules:
servers-https:
description: Servers must use HTTPS.
message: "{{property}} must start with https:// but was {{value}}"
severity: error
given: $.servers[*]
then:
field: url
function: pattern
functionOptions:
match: "^https://"
openapi.yaml:6:10 error servers-https "url must start with https:// but was http://api.example.com"
6. Aliases
When several rules look in the same place, name that place once as an alias, and refer to it with #.
aliases:
Operation:
- $.paths[*][get,put,post,delete,patch]
rules:
operation-summary:
description: Every operation has a summary.
given: "#Operation"
then:
field: summary
function: truthy
operation-id:
description: Every operation has an operationId.
given: "#Operation"
then:
field: operationId
function: truthy
openapi.yaml:9:9 warning operation-id "Every operation has an operationId."
The operation has a summary, so only the operationId rule reports.
Check your ruleset
The JSON Schema catches mistakes in a ruleset, such as a misspelled field or a given that isn't a path, before you lint anything. Using the schema shows how to use it in your editor and in CI.
Where next
- The specification: everything in the format, including
overridesand custom functions - Education discussion (#25): suggest what comes after 101