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
Authorship not recorded No authorship marker is recorded for this file. It is not presented as the provider's; it was most likely written by an API Evangelist pass before outputs were stamped.
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

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/weatherapi-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.