Numbers API · API Governance Rules

Numbers API API Rules

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

37 Rules error 16 warn 16 info 5
View Rules File View on GitHub

Rule Categories

examples global info no only openapi operation parameter paths response schema security servers tag

Rules

warn
info-title-prefix
Info title must start with "Numbers API".
$.info.title
error
info-description-required
A non-empty info.description is required.
$.info
info
info-contact-email
Info contact must include an email.
$.info.contact
warn
info-license-required
Info license block must be present.
$.info
error
openapi-version-3
Spec must be OpenAPI 3.0.x.
$.openapi
error
servers-defined
At least one server must be defined.
$
error
servers-url-required
Each server entry must define a url.
$.servers[*]
warn
servers-description-required
Each server entry should include a description.
$.servers[*]
error
paths-lowercase
Path segments must be lowercase.
$.paths.*~
error
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths.*~
error
paths-no-query-string
Paths must not embed query strings.
$.paths.*~
warn
paths-no-version-prefix
Numbers API paths are unversioned; do not introduce /v1, /v2 prefixes.
$.paths.*~
error
operation-summary-required
Every operation must have a summary.
$.paths.*[get,post,put,patch,delete,options,head]
warn
operation-summary-prefix
Operation summaries should start with "Numbers API".
$.paths.*[get,post,put,patch,delete,options,head].summary
warn
operation-description-required
Every operation must have a description.
$.paths.*[get,post,put,patch,delete,options,head]
error
operation-operationid-required
Every operation must have an operationId.
$.paths.*[get,post,put,patch,delete,options,head]
error
operation-operationid-camelcase
operationIds must be camelCase.
$.paths.*[get,post,put,patch,delete,options,head].operationId
warn
operation-operationid-verb-prefix
operationIds should start with a recognized verb.
$.paths.*[get,post,put,patch,delete,options,head].operationId
error
operation-tags-required
Every operation must declare at least one tag.
$.paths.*[get,post,put,patch,delete,options,head]
warn
global-tags-defined
A global tags array must be defined.
$
warn
tag-description-required
Each global tag must include a description.
$.tags[*]
warn
tag-title-case
Tag names must be Title Case (single word per tag).
$.tags[*].name
warn
parameter-description-required
Every parameter must include a description.
$..parameters[*]
warn
parameter-name-lowercase
Query and path parameter names must be lowercase (matches the API's style: `json`, `fragment`, `notfound`, `min`, `max`, `callback`, `write`, `default`).
$..parameters[?(@.in == 'query' || @.in == 'path')].name
error
parameter-required-flag-on-path
Path parameters must declare required:true.
$..parameters[?(@.in == 'path')]
info
parameter-example-recommended
Query parameters should include an example.
$..parameters[?(@.in == 'query')]
error
response-success-required
Every operation must declare a 2xx response.
$.paths.*[get,post,put,patch,delete,options,head].responses
error
response-description-required
Every response must include a description.
$..responses[*]
warn
response-plaintext-content
200 responses should include a text/plain representation (Numbers API default).
$.paths.*[get].responses[200].content
info
response-json-content
200 responses should also include an application/json representation.
$.paths.*[get].responses[200].content
error
no-request-body-on-get
GET operations must not declare a request body.
$.paths.*.get
warn
schema-property-snake-or-camel
Schema property names should be lowercase camelCase or snake_case; Numbers API's `Fact` object uses lowercase single-word fields (`text`, `number`, `found`, `type`, `date`, `year`).
$.components.schemas.*.properties.*~
warn
schema-types-defined
Every schema must declare a type.
$.components.schemas.*
warn
schema-description-required
Top-level schemas must include a description.
$.components.schemas.*
info
security-not-required
Numbers API is a free public API; do not declare global security requirements that would imply authentication.
$
error
only-get-methods
Numbers API exposes only GET endpoints. Do not introduce POST/PUT/PATCH/ DELETE operations.
$.paths.*[post,put,patch,delete]
info
examples-encouraged
200 responses should include named examples.
$.paths.*[get].responses[200].content.application/json

Spectral Ruleset

Raw ↑
extends: []

# Spectral ruleset for the Numbers API (numbersapi.com).
# Patterns enforced reflect the spec's dominant conventions:
#  - Title prefix "Numbers API"
#  - lowercase path segments, integer/keyword path params, no version prefix
#  - camelCase operationIds with verb prefixes (get)
#  - snake_case-friendly query parameters (matches `notfound`, `min`, `max`,
#    `callback`, `write`, `fragment`, `json`, `default`)
#  - Title Case tags grouped by fact type
#  - Plain-text responses with optional `application/json` alternative
#  - No authentication (public, free API)

rules:

  # ── INFO / METADATA ─────────────────────────────────────────────────────
  info-title-prefix:
    description: Info title must start with "Numbers API".
    message: 'info.title should begin with "Numbers API".'
    severity: warn
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        match: '^Numbers API'

  info-description-required:
    description: A non-empty info.description is required.
    message: 'info.description is required and must be at least 40 characters.'
    severity: error
    given: $.info
    then:
      field: description
      function: length
      functionOptions:
        min: 40

  info-contact-email:
    description: Info contact must include an email.
    message: 'info.contact.email is recommended ([email protected] for this provider).'
    severity: info
    given: $.info.contact
    then:
      field: email
      function: truthy

  info-license-required:
    description: Info license block must be present.
    message: 'info.license is required.'
    severity: warn
    given: $.info
    then:
      field: license
      function: truthy

  # ── OPENAPI VERSION ─────────────────────────────────────────────────────
  openapi-version-3:
    description: Spec must be OpenAPI 3.0.x.
    message: 'Spec must declare openapi version 3.0.x.'
    severity: error
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: '^3\.0\.\d+$'

  # ── SERVERS ─────────────────────────────────────────────────────────────
  servers-defined:
    description: At least one server must be defined.
    message: 'A servers entry is required (e.g. http://numbersapi.com).'
    severity: error
    given: $
    then:
      field: servers
      function: truthy

  servers-url-required:
    description: Each server entry must define a url.
    message: 'servers[].url is required.'
    severity: error
    given: $.servers[*]
    then:
      field: url
      function: truthy

  servers-description-required:
    description: Each server entry should include a description.
    message: 'servers[].description is recommended.'
    severity: warn
    given: $.servers[*]
    then:
      field: description
      function: truthy

  # ── PATHS — NAMING CONVENTIONS ──────────────────────────────────────────
  paths-lowercase:
    description: Path segments must be lowercase.
    message: 'Path "{{property}}" must use lowercase segments (e.g. /{number}/trivia).'
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: '^/[a-z0-9{}/_.-]*$'

  paths-no-trailing-slash:
    description: Paths must not end with a trailing slash.
    message: 'Path "{{property}}" must not end with a trailing slash.'
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: '/$'

  paths-no-query-string:
    description: Paths must not embed query strings.
    message: 'Path "{{property}}" must not include a query string.'
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: '\?'

  paths-no-version-prefix:
    description: Numbers API paths are unversioned; do not introduce /v1, /v2 prefixes.
    message: 'Path "{{property}}" should not include a version prefix; Numbers API is unversioned.'
    severity: warn
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: '^/v\d+/'

  # ── OPERATIONS ──────────────────────────────────────────────────────────
  operation-summary-required:
    description: Every operation must have a summary.
    message: '{{path}} is missing a summary.'
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head]
    then:
      field: summary
      function: truthy

  operation-summary-prefix:
    description: Operation summaries should start with "Numbers API".
    message: 'Operation summary should begin with "Numbers API".'
    severity: warn
    given: $.paths.*[get,post,put,patch,delete,options,head].summary
    then:
      function: pattern
      functionOptions:
        match: '^Numbers API '

  operation-description-required:
    description: Every operation must have a description.
    message: '{{path}} is missing a description.'
    severity: warn
    given: $.paths.*[get,post,put,patch,delete,options,head]
    then:
      field: description
      function: truthy

  operation-operationid-required:
    description: Every operation must have an operationId.
    message: '{{path}} is missing an operationId.'
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head]
    then:
      field: operationId
      function: truthy

  operation-operationid-camelcase:
    description: operationIds must be camelCase.
    message: 'operationId "{{value}}" must be camelCase (e.g. getTriviaFact).'
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head].operationId
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'

  operation-operationid-verb-prefix:
    description: operationIds should start with a recognized verb.
    message: 'operationId "{{value}}" should start with get/list/create/update/delete/search.'
    severity: warn
    given: $.paths.*[get,post,put,patch,delete,options,head].operationId
    then:
      function: pattern
      functionOptions:
        match: '^(get|list|create|update|delete|search|add|remove)[A-Z]'

  operation-tags-required:
    description: Every operation must declare at least one tag.
    message: '{{path}} must declare a tag.'
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head]
    then:
      field: tags
      function: truthy

  # ── TAGS ────────────────────────────────────────────────────────────────
  global-tags-defined:
    description: A global tags array must be defined.
    message: 'A top-level tags array is required.'
    severity: warn
    given: $
    then:
      field: tags
      function: truthy

  tag-description-required:
    description: Each global tag must include a description.
    message: 'Tag "{{value}}" is missing a description.'
    severity: warn
    given: $.tags[*]
    then:
      field: description
      function: truthy

  tag-title-case:
    description: Tag names must be Title Case (single word per tag).
    message: 'Tag "{{value}}" must be Title Case (e.g. Trivia, Math, Date, Year, Batch).'
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: '^[A-Z][a-zA-Z]*( [A-Z][a-zA-Z]*)*$'

  # ── PARAMETERS ──────────────────────────────────────────────────────────
  parameter-description-required:
    description: Every parameter must include a description.
    message: 'Parameter "{{value}}" is missing a description.'
    severity: warn
    given: $..parameters[*]
    then:
      field: description
      function: truthy

  parameter-name-lowercase:
    description: >-
      Query and path parameter names must be lowercase (matches the API's
      style: `json`, `fragment`, `notfound`, `min`, `max`, `callback`,
      `write`, `default`).
    message: 'Parameter "{{value}}" must be lowercase.'
    severity: warn
    given: $..parameters[?(@.in == 'query' || @.in == 'path')].name
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'

  parameter-required-flag-on-path:
    description: Path parameters must declare required:true.
    message: 'Path parameter "{{value}}" must have required:true.'
    severity: error
    given: $..parameters[?(@.in == 'path')]
    then:
      field: required
      function: truthy

  parameter-example-recommended:
    description: Query parameters should include an example.
    message: 'Parameter "{{value}}" should include an example.'
    severity: info
    given: $..parameters[?(@.in == 'query')]
    then:
      field: example
      function: truthy

  # ── RESPONSES ───────────────────────────────────────────────────────────
  response-success-required:
    description: Every operation must declare a 2xx response.
    message: '{{path}} must declare a 200 response.'
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head].responses
    then:
      field: '200'
      function: truthy

  response-description-required:
    description: Every response must include a description.
    message: 'Response "{{property}}" is missing a description.'
    severity: error
    given: $..responses[*]
    then:
      field: description
      function: truthy

  response-plaintext-content:
    description: 200 responses should include a text/plain representation (Numbers API default).
    message: '200 response should include a text/plain content type.'
    severity: warn
    given: $.paths.*[get].responses[200].content
    then:
      field: 'text/plain'
      function: truthy

  response-json-content:
    description: 200 responses should also include an application/json representation.
    message: '200 response should also include an application/json content type.'
    severity: info
    given: $.paths.*[get].responses[200].content
    then:
      field: 'application/json'
      function: truthy

  # ── REQUEST BODIES ──────────────────────────────────────────────────────
  no-request-body-on-get:
    description: GET operations must not declare a request body.
    message: '{{path}} GET must not declare a requestBody.'
    severity: error
    given: $.paths.*.get
    then:
      field: requestBody
      function: falsy

  # ── SCHEMAS — PROPERTY NAMING ───────────────────────────────────────────
  schema-property-snake-or-camel:
    description: >-
      Schema property names should be lowercase camelCase or snake_case;
      Numbers API's `Fact` object uses lowercase single-word fields
      (`text`, `number`, `found`, `type`, `date`, `year`).
    message: 'Schema property "{{property}}" must be camelCase or snake_case.'
    severity: warn
    given: $.components.schemas.*.properties.*~
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9_]*$'

  schema-types-defined:
    description: Every schema must declare a type.
    message: 'Schema "{{property}}" must declare a type.'
    severity: warn
    given: $.components.schemas.*
    then:
      field: type
      function: truthy

  schema-description-required:
    description: Top-level schemas must include a description.
    message: 'Schema "{{property}}" must include a description.'
    severity: warn
    given: $.components.schemas.*
    then:
      field: description
      function: truthy

  # ── SECURITY ────────────────────────────────────────────────────────────
  security-not-required:
    description: >-
      Numbers API is a free public API; do not declare global security
      requirements that would imply authentication.
    message: 'Numbers API does not require authentication; security should be absent.'
    severity: info
    given: $
    then:
      field: security
      function: falsy

  # ── HTTP METHOD CONVENTIONS ─────────────────────────────────────────────
  only-get-methods:
    description: >-
      Numbers API exposes only GET endpoints. Do not introduce POST/PUT/PATCH/
      DELETE operations.
    message: '{{path}} introduces a non-GET method; Numbers API only exposes GETs.'
    severity: error
    given: $.paths.*[post,put,patch,delete]
    then:
      function: undefined

  # ── GENERAL QUALITY ─────────────────────────────────────────────────────
  examples-encouraged:
    description: 200 responses should include named examples.
    message: '200 response should include an `examples:` block.'
    severity: info
    given: $.paths.*[get].responses[200].content.application/json
    then:
      field: examples
      function: truthy