WeatherAPI · API Governance Rules

WeatherAPI API Rules

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

37 Rules error 11 warn 21 info 5
View Rules File View on GitHub

Rule Categories

examples get info no openapi operation parameter paths requestbody response schema security servers tags

Rules

warn
info-title-format
Info title should begin with "WeatherAPI" to match the provider naming convention.
$.info.title
error
info-description-required
Info description must be present and substantive (>= 80 chars).
$.info
error
info-version-required
A SemVer-ish version is required on info.
$.info
info
info-contact-recommended
Provide a contact block so consumers can reach support.
$.info
info
info-license-recommended
Provide a license so consumers can understand reuse terms.
$.info
warn
openapi-version-3-1
Use OpenAPI 3.1.x (matches the official WeatherAPI.com spec).
$.openapi
error
servers-defined
At least one server URL must be defined.
$
warn
servers-https-required
HTTPS server URL must be present (https://api.weatherapi.com/v1).
$.servers[*].url
warn
paths-json-suffix
WeatherAPI paths use the `.json` suffix (legacy XML variants live at the same root).
$.paths.*~
warn
paths-lowercase-segments
Path segments must be lowercase (no camelCase or PascalCase).
$.paths.*~
error
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths.*~
error
operation-operationid-required
Every operation must declare an operationId.
$.paths[*][get,post,put,patch,delete]
warn
operation-operationid-camelcase
WeatherAPI operationIds are camelCase (e.g. getCurrentWeather, ipLookup, searchLocations).
$.paths[*][get,post,put,patch,delete].operationId
error
operation-summary-required
Every operation must have a summary.
$.paths[*][get,post,put,patch,delete]
warn
operation-summary-weatherapi-prefix
Operation summaries should be prefixed with "WeatherAPI" so they identify the provider in catalog UIs.
$.paths[*][get,post,put,patch,delete].summary
error
operation-description-required
Every operation must have a description.
$.paths[*][get,post,put,patch,delete]
error
operation-tags-required
Every operation must declare at least one tag.
$.paths[*][get,post,put,patch,delete]
info
operation-microcks-extension
Each operation should expose `x-microcks-operation` so it can be mocked via Microcks.
$.paths[*][get,post,put,patch,delete]
warn
tags-title-case
Global tags must use Title Case (Weather, History, Marine, Future, Geo, Sports, Alerts).
$.tags[*].name
warn
tags-description-required
Each global tag should have a description.
$.tags[*]
warn
parameter-description-required
Every parameter must have a description.
$.components.parameters[*]
warn
parameter-snake-case
WeatherAPI query parameters use snake_case (e.g. end_dt, current_fields, q, dt).
$.components.parameters[*].name
info
parameter-q-required-on-data-endpoints
Every data-returning operation should accept the `q` location parameter (except internal/bulk variants).
$.paths[*][get]
error
response-200-required
Every GET operation must define a 200 response.
$.paths[*][get].responses
warn
response-400-required
Define a 400 response for client errors (matches the WeatherAPI ErrorResponse shape).
$.paths[*][get,post,put,patch,delete].responses
warn
response-401-required
Define a 401 response for missing/invalid API keys.
$.paths[*][get,post,put,patch,delete].responses
warn
response-403-required
Define a 403 response for plan/quota or geographic restrictions.
$.paths[*][get,post,put,patch,delete].responses
warn
response-json-content
Responses must use application/json content type (WeatherAPI also offers XML, but JSON is canonical).
$.paths[*][get,post,put,patch,delete].responses[*].content
warn
requestbody-json-content
Request bodies should declare application/json content.
$.paths[*][post,put,patch].requestBody.content
warn
schema-property-snake-case
Schema properties use snake_case (temp_c, last_updated, wind_kph, feelslike_c).
$.components.schemas[*].properties[*]~
warn
schema-description-required
Top-level component schemas should have a description.
$.components.schemas[*]
warn
schema-type-required
Top-level schemas with properties should declare a type.
$.components.schemas[?(@.properties)]
error
security-defined
A global security requirement must be declared.
$
warn
security-apikey-scheme
WeatherAPI uses a single ApiKeyAuth security scheme via the `key` query parameter.
$.components.securitySchemes.ApiKeyAuth
error
get-no-request-body
GET operations must not declare a request body.
$.paths[*][get]
warn
no-empty-descriptions
Descriptions must not be empty strings.
$..description
info
examples-encouraged
Schema properties should provide an example value where realistic.
$.components.schemas[*].properties[*]

Spectral Ruleset

Raw ↑
# WeatherAPI.com — Spectral Ruleset
# Generated from analysis of openapi/weatherapi-openapi-original.yml.
# Enforces the conventions observed across the WeatherAPI.com API surface:
#   - Single API key auth via the `key` query parameter
#   - .json suffixed paths under /v1 (snake_case-free, single-segment)
#   - camelCase operationIds (getCurrentWeather, getForecast, ipLookup, ...)
#   - snake_case schema property names (temp_c, last_updated, wind_kph)
#   - Title Case tags grouped by domain (Weather, History, Marine, Future, Geo, Sports, Alerts)
#   - Provider-prefixed summaries ("WeatherAPI Current / Real-time Weather")

extends:
  - spectral:oas

rules:

  # ──────────────────────────────────────────────────────────────────
  # INFO / METADATA
  # ──────────────────────────────────────────────────────────────────

  info-title-format:
    description: Info title should begin with "WeatherAPI" to match the provider naming convention.
    message: 'info.title should start with "WeatherAPI" (got "{{value}}")'
    severity: warn
    given: "$.info.title"
    then:
      function: pattern
      functionOptions:
        match: "^WeatherAPI"

  info-description-required:
    description: Info description must be present and substantive (>= 80 chars).
    severity: error
    given: "$.info"
    then:
      - field: description
        function: truthy
      - field: description
        function: length
        functionOptions:
          min: 80

  info-version-required:
    description: A SemVer-ish version is required on info.
    severity: error
    given: "$.info"
    then:
      field: version
      function: truthy

  info-contact-recommended:
    description: Provide a contact block so consumers can reach support.
    severity: info
    given: "$.info"
    then:
      field: contact
      function: truthy

  info-license-recommended:
    description: Provide a license so consumers can understand reuse terms.
    severity: info
    given: "$.info"
    then:
      field: license
      function: truthy

  # ──────────────────────────────────────────────────────────────────
  # OPENAPI VERSION
  # ──────────────────────────────────────────────────────────────────

  openapi-version-3-1:
    description: Use OpenAPI 3.1.x (matches the official WeatherAPI.com spec).
    message: 'OpenAPI version should be 3.1.x (got "{{value}}")'
    severity: warn
    given: "$.openapi"
    then:
      function: pattern
      functionOptions:
        match: "^3\\.1\\."

  # ──────────────────────────────────────────────────────────────────
  # SERVERS
  # ──────────────────────────────────────────────────────────────────

  servers-defined:
    description: At least one server URL must be defined.
    severity: error
    given: "$"
    then:
      field: servers
      function: truthy

  servers-https-required:
    description: HTTPS server URL must be present (https://api.weatherapi.com/v1).
    severity: warn
    given: "$.servers[*].url"
    then:
      function: pattern
      functionOptions:
        match: "^https://api\\.weatherapi\\.com/v1"

  # ──────────────────────────────────────────────────────────────────
  # PATHS — NAMING CONVENTIONS
  # ──────────────────────────────────────────────────────────────────

  paths-json-suffix:
    description: WeatherAPI paths use the `.json` suffix (legacy XML variants live at the same root).
    message: 'Path should end in .json (e.g. /current.json, /forecast.json)'
    severity: warn
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        match: "\\.json(\\#bulk)?$"

  paths-lowercase-segments:
    description: Path segments must be lowercase (no camelCase or PascalCase).
    message: "Path segment '{{value}}' should be lowercase."
    severity: warn
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        match: "^/[a-z0-9./_#-]+$"

  paths-no-trailing-slash:
    description: Paths must not end with a trailing slash.
    severity: error
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        notMatch: ".+/$"

  # ──────────────────────────────────────────────────────────────────
  # OPERATIONS
  # ──────────────────────────────────────────────────────────────────

  operation-operationid-required:
    description: Every operation must declare an operationId.
    severity: error
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: operationId
      function: truthy

  operation-operationid-camelcase:
    description: WeatherAPI operationIds are camelCase (e.g. getCurrentWeather, ipLookup, searchLocations).
    message: 'operationId "{{value}}" should be camelCase.'
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-zA-Z0-9]+$"

  operation-summary-required:
    description: Every operation must have a summary.
    severity: error
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: summary
      function: truthy

  operation-summary-weatherapi-prefix:
    description: Operation summaries should be prefixed with "WeatherAPI" so they identify the provider in catalog UIs.
    message: 'summary "{{value}}" should start with "WeatherAPI".'
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].summary"
    then:
      function: pattern
      functionOptions:
        match: "^WeatherAPI"

  operation-description-required:
    description: Every operation must have a description.
    severity: error
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: description
      function: truthy

  operation-tags-required:
    description: Every operation must declare at least one tag.
    severity: error
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: tags
      function: truthy

  operation-microcks-extension:
    description: Each operation should expose `x-microcks-operation` so it can be mocked via Microcks.
    severity: info
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: x-microcks-operation
      function: truthy

  # ──────────────────────────────────────────────────────────────────
  # TAGS
  # ──────────────────────────────────────────────────────────────────

  tags-title-case:
    description: Global tags must use Title Case (Weather, History, Marine, Future, Geo, Sports, Alerts).
    message: 'Tag "{{value}}" should be Title Case.'
    severity: warn
    given: "$.tags[*].name"
    then:
      function: pattern
      functionOptions:
        match: "^[A-Z][A-Za-z0-9]*( [A-Z][A-Za-z0-9]*)*$"

  tags-description-required:
    description: Each global tag should have a description.
    severity: warn
    given: "$.tags[*]"
    then:
      field: description
      function: truthy

  # ──────────────────────────────────────────────────────────────────
  # PARAMETERS
  # ──────────────────────────────────────────────────────────────────

  parameter-description-required:
    description: Every parameter must have a description.
    severity: warn
    given: "$.components.parameters[*]"
    then:
      field: description
      function: truthy

  parameter-snake-case:
    description: WeatherAPI query parameters use snake_case (e.g. end_dt, current_fields, q, dt).
    message: "Parameter name '{{value}}' should be snake_case."
    severity: warn
    given: "$.components.parameters[*].name"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-z0-9_]*$"

  parameter-q-required-on-data-endpoints:
    description: Every data-returning operation should accept the `q` location parameter (except internal/bulk variants).
    severity: info
    given: "$.paths[*][get]"
    then:
      function: truthy
      field: parameters

  # ──────────────────────────────────────────────────────────────────
  # RESPONSES
  # ──────────────────────────────────────────────────────────────────

  response-200-required:
    description: Every GET operation must define a 200 response.
    severity: error
    given: "$.paths[*][get].responses"
    then:
      field: "200"
      function: truthy

  response-400-required:
    description: Define a 400 response for client errors (matches the WeatherAPI ErrorResponse shape).
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].responses"
    then:
      field: "400"
      function: truthy

  response-401-required:
    description: Define a 401 response for missing/invalid API keys.
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].responses"
    then:
      field: "401"
      function: truthy

  response-403-required:
    description: Define a 403 response for plan/quota or geographic restrictions.
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].responses"
    then:
      field: "403"
      function: truthy

  response-json-content:
    description: Responses must use application/json content type (WeatherAPI also offers XML, but JSON is canonical).
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].responses[*].content"
    then:
      field: "application/json"
      function: truthy

  # ──────────────────────────────────────────────────────────────────
  # REQUEST BODIES
  # ──────────────────────────────────────────────────────────────────

  requestbody-json-content:
    description: Request bodies should declare application/json content.
    severity: warn
    given: "$.paths[*][post,put,patch].requestBody.content"
    then:
      field: "application/json"
      function: truthy

  # ──────────────────────────────────────────────────────────────────
  # SCHEMAS — PROPERTY NAMING
  # ──────────────────────────────────────────────────────────────────

  schema-property-snake-case:
    description: Schema properties use snake_case (temp_c, last_updated, wind_kph, feelslike_c).
    message: "Schema property '{{property}}' should be snake_case."
    severity: warn
    given: "$.components.schemas[*].properties[*]~"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-z0-9_]*$"

  schema-description-required:
    description: Top-level component schemas should have a description.
    severity: warn
    given: "$.components.schemas[*]"
    then:
      field: description
      function: truthy

  schema-type-required:
    description: Top-level schemas with properties should declare a type.
    severity: warn
    given: "$.components.schemas[?(@.properties)]"
    then:
      field: type
      function: truthy

  # ──────────────────────────────────────────────────────────────────
  # SECURITY
  # ──────────────────────────────────────────────────────────────────

  security-defined:
    description: A global security requirement must be declared.
    severity: error
    given: "$"
    then:
      field: security
      function: truthy

  security-apikey-scheme:
    description: WeatherAPI uses a single ApiKeyAuth security scheme via the `key` query parameter.
    severity: warn
    given: "$.components.securitySchemes.ApiKeyAuth"
    then:
      - field: type
        function: pattern
        functionOptions:
          match: "^apiKey$"
      - field: in
        function: pattern
        functionOptions:
          match: "^query$"
      - field: name
        function: pattern
        functionOptions:
          match: "^key$"

  # ──────────────────────────────────────────────────────────────────
  # HTTP METHOD CONVENTIONS
  # ──────────────────────────────────────────────────────────────────

  get-no-request-body:
    description: GET operations must not declare a request body.
    severity: error
    given: "$.paths[*][get]"
    then:
      field: requestBody
      function: falsy

  # ──────────────────────────────────────────────────────────────────
  # GENERAL QUALITY
  # ──────────────────────────────────────────────────────────────────

  no-empty-descriptions:
    description: Descriptions must not be empty strings.
    severity: warn
    given: "$..description"
    then:
      function: truthy

  examples-encouraged:
    description: Schema properties should provide an example value where realistic.
    severity: info
    given: "$.components.schemas[*].properties[*]"
    then:
      field: example
      function: truthy