Otter · API Governance Rules

Otter API Rules

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

29 Rules error 6 warn 13 info 10
View Rules File View on GitHub

Rule Categories

get global info microcks no openapi operation parameter path request response schema security server servers store tag

Rules

error
info-title-required
API must declare an info.title.
$.info
warn
info-description-required
API must have a meaningful info.description.
$.info
warn
info-contact-required
API must declare a maintainer contact.
$.info
error
info-version-required
API must declare info.version.
$.info
warn
openapi-version-3
Specs should target OpenAPI 3.0.x as the Otter Public API does.
$.openapi
error
servers-defined
At least one server must be defined.
$.servers
warn
server-description-required
Each server should describe how its host is provisioned (Otter hosts are account-specific).
$.servers[*]
warn
path-no-trailing-slash
Paths must not end with a trailing slash.
$.paths[*]~
info
path-segments-lower
Static path segments use lower-case (camelCase placeholders like {orderId} are allowed).
$.paths[*]~
info
path-versioned
Otter Public API paths are versioned; expect a /v1 segment.
$.paths[*]~
error
operation-operationid-required
Every operation must declare an operationId.
$.paths[*][get,post,put,patch,delete]
warn
operation-operationid-camelcase
operationIds follow camelCase (createOrder, getManagerOrder).
$.paths[*][get,post,put,patch,delete].operationId
warn
operation-summary-required
Every operation must declare a summary.
$.paths[*][get,post,put,patch,delete]
info
operation-summary-otter-prefix
Operation summaries are prefixed with the provider name "Otter".
$.paths[*][get,post,put,patch,delete].summary
warn
operation-tags-required
Every operation must be tagged.
$.paths[*][get,post,put,patch,delete]
warn
tag-title-case
Tags use Title Case with spaces (e.g. "Orders Endpoints", "Menus Webhooks").
$.paths[*][get,post,put,patch,delete].tags[*]
info
global-tags-described
Global tag definitions should carry a description.
$.tags[*]
info
parameter-description-required
Parameters should be described.
$.paths[*][get,post,put,patch,delete].parameters[*]
warn
parameter-schema-required
Parameters must define a schema with a type.
$.paths[*][get,post,put,patch,delete].parameters[?(@.in != 'body')]
info
store-id-header-name
Store-scoped requests identify the store via the X-Store-Id header.
$.paths[*][get,post,put,patch,delete].parameters[?(@.in=='header' && @.name)]
info
request-body-json
Request bodies should offer application/json content.
$.paths[*][post,put,patch].requestBody.content
warn
response-success-defined
Operations must define at least one 2xx response.
$.paths[*][get,post,put,patch,delete].responses
warn
response-description-required
Every response must have a description.
$.paths[*][get,post,put,patch,delete].responses[*]
info
schema-type-defined
Component schemas should define a type or composition keyword.
$.components.schemas[*]
error
security-schemes-defined
Security schemes must be defined (Otter uses OAuth 2.0 bearer tokens).
$.components.securitySchemes
info
security-oauth2-present
The OAuth2.0 security scheme should be present.
$.components.securitySchemes
error
get-no-request-body
GET operations must not define a request body.
$.paths[*].get
warn
no-empty-description
Descriptions, where present, must not be empty.
$..description
info
microcks-operation-encouraged
Operations should carry x-microcks-operation for mock-server compatibility.
$.paths[*][get,post,put,patch,delete]

Spectral Ruleset

Raw ↑
# Otter Public API — Spectral Ruleset
# Generated by the API Evangelist profiling pipeline from openapi/otter-public-api-openapi.yml
# Encodes the conventions observed in the Otter (TryOtter) Public API:
#   - OpenAPI 3.0.x
#   - OAuth 2.0 (client_credentials + authorization_code) bearer tokens
#   - camelCase operationIds, Title Case tags ("Orders Endpoints", "Menus Webhooks")
#   - versioned, kebab/lower path segments under /v1 and /manager/{domain}/v1
#   - snake_case-leaning JSON schema properties, X-Store-Id / X-HMAC-SHA256 headers
rules:

  # ── INFO / METADATA ─────────────────────────────────────────────
  info-title-required:
    description: API must declare an info.title.
    given: $.info
    severity: error
    then:
      field: title
      function: truthy
  info-description-required:
    description: API must have a meaningful info.description.
    given: $.info
    severity: warn
    then:
      field: description
      function: truthy
  info-contact-required:
    description: API must declare a maintainer contact.
    given: $.info
    severity: warn
    then:
      field: contact
      function: truthy
  info-version-required:
    description: API must declare info.version.
    given: $.info
    severity: error
    then:
      field: version
      function: truthy

  # ── OPENAPI VERSION ─────────────────────────────────────────────
  openapi-version-3:
    description: Specs should target OpenAPI 3.0.x as the Otter Public API does.
    given: $.openapi
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: '^3\.0\.\d+$'

  # ── SERVERS ─────────────────────────────────────────────────────
  servers-defined:
    description: At least one server must be defined.
    given: $.servers
    severity: error
    then:
      function: truthy
  server-description-required:
    description: Each server should describe how its host is provisioned (Otter hosts are account-specific).
    given: $.servers[*]
    severity: warn
    then:
      field: description
      function: truthy

  # ── PATHS — NAMING CONVENTIONS ──────────────────────────────────
  path-no-trailing-slash:
    description: Paths must not end with a trailing slash.
    given: $.paths[*]~
    severity: warn
    then:
      function: pattern
      functionOptions:
        notMatch: '.+/$'
  path-segments-lower:
    description: Static path segments use lower-case (camelCase placeholders like {orderId} are allowed).
    given: $.paths[*]~
    severity: info
    then:
      function: pattern
      functionOptions:
        match: '^(/(v1|manager|[a-z0-9-]+|\{[A-Za-z0-9]+\}))+$'
  path-versioned:
    description: Otter Public API paths are versioned; expect a /v1 segment.
    given: $.paths[*]~
    severity: info
    then:
      function: pattern
      functionOptions:
        match: 'v1'

  # ── OPERATIONS ──────────────────────────────────────────────────
  operation-operationid-required:
    description: Every operation must declare an operationId.
    given: $.paths[*][get,post,put,patch,delete]
    severity: error
    then:
      field: operationId
      function: truthy
  operation-operationid-camelcase:
    description: operationIds follow camelCase (createOrder, getManagerOrder).
    given: $.paths[*][get,post,put,patch,delete].operationId
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]+$'
  operation-summary-required:
    description: Every operation must declare a summary.
    given: $.paths[*][get,post,put,patch,delete]
    severity: warn
    then:
      field: summary
      function: truthy
  operation-summary-otter-prefix:
    description: Operation summaries are prefixed with the provider name "Otter".
    given: $.paths[*][get,post,put,patch,delete].summary
    severity: info
    then:
      function: pattern
      functionOptions:
        match: '^Otter '
  operation-tags-required:
    description: Every operation must be tagged.
    given: $.paths[*][get,post,put,patch,delete]
    severity: warn
    then:
      field: tags
      function: truthy

  # ── TAGS ────────────────────────────────────────────────────────
  tag-title-case:
    description: Tags use Title Case with spaces (e.g. "Orders Endpoints", "Menus Webhooks").
    given: $.paths[*][get,post,put,patch,delete].tags[*]
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: '^[A-Z][A-Za-z]+( [A-Z][A-Za-z]+)*$'
  global-tags-described:
    description: Global tag definitions should carry a description.
    given: $.tags[*]
    severity: info
    then:
      field: description
      function: truthy

  # ── PARAMETERS ──────────────────────────────────────────────────
  parameter-description-required:
    description: Parameters should be described.
    given: $.paths[*][get,post,put,patch,delete].parameters[*]
    severity: info
    then:
      field: description
      function: truthy
  parameter-schema-required:
    description: Parameters must define a schema with a type.
    given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in != 'body')]
    severity: warn
    then:
      field: schema
      function: truthy
  store-id-header-name:
    description: Store-scoped requests identify the store via the X-Store-Id header.
    given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in=='header' && @.name)]
    severity: info
    then:
      field: name
      function: pattern
      functionOptions:
        match: '^(X-Store-Id|X-HMAC-SHA256|Authorization|[A-Za-z-]+)$'

  # ── REQUEST BODIES ──────────────────────────────────────────────
  request-body-json:
    description: Request bodies should offer application/json content.
    given: $.paths[*][post,put,patch].requestBody.content
    severity: info
    then:
      field: application/json
      function: truthy

  # ── RESPONSES ───────────────────────────────────────────────────
  response-success-defined:
    description: Operations must define at least one 2xx response.
    given: $.paths[*][get,post,put,patch,delete].responses
    severity: warn
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          patternProperties:
            '^2\d\d$': true
          minProperties: 1
  response-description-required:
    description: Every response must have a description.
    given: $.paths[*][get,post,put,patch,delete].responses[*]
    severity: warn
    then:
      field: description
      function: truthy

  # ── SCHEMAS — PROPERTY NAMING ───────────────────────────────────
  schema-type-defined:
    description: Component schemas should define a type or composition keyword.
    given: $.components.schemas[*]
    severity: info
    then:
      function: schema
      functionOptions:
        schema:
          anyOf:
            - required: [type]
            - required: [allOf]
            - required: [oneOf]
            - required: [anyOf]
            - required: [$ref]
            - required: [enum]

  # ── SECURITY ────────────────────────────────────────────────────
  security-schemes-defined:
    description: Security schemes must be defined (Otter uses OAuth 2.0 bearer tokens).
    given: $.components.securitySchemes
    severity: error
    then:
      function: truthy
  security-oauth2-present:
    description: The OAuth2.0 security scheme should be present.
    given: $.components.securitySchemes
    severity: info
    then:
      field: OAuth2.0
      function: truthy

  # ── HTTP METHOD CONVENTIONS ─────────────────────────────────────
  get-no-request-body:
    description: GET operations must not define a request body.
    given: $.paths[*].get
    severity: error
    then:
      field: requestBody
      function: falsy

  # ── GENERAL QUALITY ─────────────────────────────────────────────
  no-empty-description:
    description: Descriptions, where present, must not be empty.
    given: $..description
    severity: warn
    then:
      function: truthy
  microcks-operation-encouraged:
    description: Operations should carry x-microcks-operation for mock-server compatibility.
    given: $.paths[*][get,post,put,patch,delete]
    severity: info
    then:
      field: x-microcks-operation
      function: truthy