# 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