Stoplight · API Governance Rules

Stoplight — style guides rulebook series rules

Spectral linting rules defining API design standards and conventions for Stoplight.

18 Rules error 10 warn 6
Published by Stoplight Served by the provider at https://github.com/stoplightio/style-guides-rulebook-series/blob/454313097a63c60c1d5667923546e5d73d7b4568/.spectral.json; the copy below was fetched from there.
View Rules File View on GitHub

Rule Categories

oas2 oas3 path paths query resource server status

Rules

error
oas3-always-use-https
$.servers[*].url
warn
oas2-always-use-https
$.schemes.*
error
server-lowercase
$.servers[*].url
error
server-has-api
$.servers[*].url
error
server-version
$.servers[*].url
off
server-major-version-only
$.servers[*].url
error
path-casing
$.paths
warn
resource-names-plural
$.paths
error
paths-no-trailing-slash
$.paths
error
paths-no-file-extensions
$.paths
error
paths-no-http-verbs
$.paths
off
paths-version-number
$.paths
warn
paths-avoid-special-characters
$.paths
warn
paths-no-query-params
$.paths
error
path-parameters-snake-case
#Request_Parameter_Path
error
query-parameters-snake-case
#Request_Parameter_Query
warn
path-parameters-on-path-only
$.paths[*][*].parameters[?(@.in == 'path')]
warn
status-path-defined
$.paths~

Spectral Ruleset

Raw ↑
# harvested from https://github.com/stoplightio/style-guides-rulebook-series/blob/454313097a63c60c1d5667923546e5d73d7b4568/.spectral.json on 2026-10-09 — a Spectral ruleset published in the provider's own GitHub repository (stoplightio/style-guides-rulebook-series); found by GitHub code search, fetched verbatim and converted from JSON to YAML
x-method: harvested
x-stamped: 2026-10-09
x-source-url: https://github.com/stoplightio/style-guides-rulebook-series/blob/454313097a63c60c1d5667923546e5d73d7b4568/.spectral.json
description: ''
formats:
- oas2
- oas3
- oas3.0
- oas3.1
aliases:
  Request_Parameter_Query:
    description: ''
    targets:
    - formats:
      - oas3
      given:
      - $.paths[*].parameters[?(@.in == 'query')].name
      - $.paths[*][*].parameters[?(@.in == 'query')].name
      - $.components.parameters[?(@.in == 'query')].name
    - formats:
      - oas2
      given:
      - $.paths[*].parameters[?(@.in == 'query')].name
      - $.paths[*][*].parameters[?(@.in == 'query')].name
      - $.components.parameters[?(@.in == 'query')].name
  Request_Parameter_Path:
    description: ''
    targets:
    - formats:
      - oas3
      given:
      - $.paths[*].parameters[?(@.in == 'path')].name
      - $.paths[*][*].parameters[?(@.in == 'path')].name
      - $.components.parameters[?(@.in == 'path')].name
    - formats:
      - oas2
      given:
      - $.paths[*].parameters[?(@.in == 'path')].name
      - $.paths[*][*].parameters[?(@.in == 'path')].name
      - $.components.parameters[?(@.in == 'path')].name
rules:
  oas3-always-use-https:
    given:
    - $.servers[*].url
    severity: error
    then:
      function: pattern
      functionOptions:
        match: (http:\/\/localhost)|(https).*
    message: Servers must use the HTTPS protocol except when using localhost
    formats:
    - oas3
  oas2-always-use-https:
    given:
    - $.schemes.*
    severity: warn
    then:
      function: enumeration
      functionOptions:
        values:
        - https
    message: Servers must use the HTTPS protocol
    formats:
    - oas2
  server-lowercase:
    given:
    - $.servers[*].url
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^[^A-Z]*$
    message: Server URL must be lowercase
    formats:
    - oas3
  server-has-api:
    given:
    - $.servers[*].url
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^.*\/api/?.*
    message: Server must have /api
    formats:
    - oas3
  server-version:
    given:
    - $.servers[*].url
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^.*\/v[1-9]
    message: Server must end with a version
    formats:
    - oas3
  server-major-version-only:
    given:
    - $.servers[*].url
    severity: 'off'
    then:
      function: pattern
      functionOptions:
        notMatch: \.
    message: Server should only have major versions
    formats:
    - oas3
  path-casing:
    given:
    - $.paths
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^\/([a-z0-9]+(-[a-z0-9]+)*)?(\/[a-z0-9]+(-[a-z0-9]+)*|\/{.+})*$
      field: '@key'
    message: Paths must be kebab-case
  resource-names-plural:
    given:
    - $.paths
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^((\/v\d+)*((\/[\w+-]*s)(\/\{.*\})*)*)$
      field: '@key'
    message: Resource names should generally be plural
  paths-no-trailing-slash:
    given:
    - $.paths
    severity: error
    then:
      function: pattern
      functionOptions:
        notMatch: \/$
      field: '@key'
    message: Paths must not end with a trailing slash
  paths-no-file-extensions:
    given:
    - $.paths
    severity: error
    then:
      function: pattern
      functionOptions:
        notMatch: (JSON|json|XML|xml)
      field: '@key'
    message: Paths must not have file extensions
  paths-no-http-verbs:
    given:
    - $.paths
    severity: error
    then:
      function: pattern
      functionOptions:
        notMatch: (GET|PUT|POST|DELETE|LIST|CREATE|REMOVE|get|put|post|delete|list|create|remove|Get|Put|Post|Delete|List|Create|Remove)
      field: '@key'
    message: Paths must not have HTTP verbs in them
  paths-version-number:
    given:
    - $.paths
    severity: 'off'
    then:
      function: pattern
      functionOptions:
        match: ^(\/v[1-9]|\/version[1-9])
      field: '@key'
    message: Paths must have a version in them
  paths-avoid-special-characters:
    given:
    - $.paths
    severity: warn
    then:
      function: pattern
      functionOptions:
        notMatch: ^(.*)([\$&+,;=?@%]+)(.*)$
        match: ''
      field: '@key'
    message: Avoid using special characters in paths
  paths-no-query-params:
    given:
    - $.paths
    severity: warn
    then:
      function: pattern
      functionOptions:
        notMatch: \?
      field: '@key'
    message: Paths should not have query parameters in them. They should be defined
      separately in the OpenAPI.
  path-parameters-snake-case:
    given:
    - '#Request_Parameter_Path'
    severity: error
    then:
      function: casing
      functionOptions:
        type: snake
        disallowDigits: true
      field: name
    message: Path parameters should be snake_case and not contain digits
  query-parameters-snake-case:
    given:
    - '#Request_Parameter_Query'
    severity: error
    then:
      function: casing
      functionOptions:
        type: snake
        disallowDigits: true
    message: Query parameters should be snake_case and not contain digits
  path-parameters-on-path-only:
    given:
    - $.paths[*][*].parameters[?(@.in == 'path')]
    severity: warn
    then:
      function: falsy
    message: Path parameters should be defined on the path level instead of the operation
      level.
  status-path-defined:
    given:
    - $.paths~
    severity: warn
    then:
      function: truthy
      field: \/status
    message: APIs MUST have a status path defined (`/status`)

Work with this as data

Every ruleset here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for spectral rules

4 MCP tools reach this
  • find_rulesBrowse and filter every ruleset in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This ruleset
curl "https://apis.io/api/v1/rules/stoplight-style-guides-rulebook-series-spectral-rules"
All spectral rules
curl "https://apis.io/api/v1/rules?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.