Files
weatherreporter/docs/integrations/weatherapi.md

149 lines
7.0 KiB
Markdown

# Weather API Integration
Weatherreporter fetches normalized weather inputs from a configured Weather API
base URL. This guide defines the HTTP contract the service must satisfy; it is
not a general Weather API reference. Configuration values are defined in the
[configuration reference](../config.md). Normalization and collection behavior
are documented in [Weather data internals](../internal/weather-data.md) and
[Collection internals](../internal/collect.md).
## Base URL And Requests
`weather_api.base_url` must be an absolute HTTP(S) URL. Weatherreporter joins
each endpoint path to the configured base URL path, so a service hosted under a
path prefix must keep that prefix available. Requests use `GET` and carry the
configured timeout on every HTTP attempt.
Every request sends `format` and, except where noted below, `units`. The
configured format must be `json`.
Before retrieving sources, Weatherreporter warms up
`/conditions/current` with the same `format`, `units`, and `precision` query
parameters used for current conditions. The warmup only requires a readable
2xx response; its body is not decoded. Failure after its internal retry budget
stops the fetch before source requests begin.
## Endpoints And Query Parameters
The adapter makes one source request for each endpoint after a successful
warmup, subject to retry on transient failures.
| Source | Endpoint | Query parameters | Availability |
| --- | --- | --- | --- |
| Observations | `/observations` | `format`, `units`, `precision` | Optional |
| Current conditions | `/conditions/current` | `format`, `units`, `precision` | Optional |
| Hourly forecast | `/forecast/hourly` | `format`, `units`, `precision`, `tz` | Required |
| Narrative forecast | `/forecast/narrative` | `format`, `units`, `precision`, `tz` | Optional |
| Active alerts | `/alerts/active` | `format`, `units` | Optional; `data: null` means checked with no active alerts |
| Forecast discussion | `/discussion` | `format`, `units`, `tz` | Optional |
| Weather story | `/weatherstories/latest` | `format` | Optional |
| SPC convective outlooks | `/outlooks/convective` | `format`, `tz` | Optional; non-null empty lists are checked empty data |
`precision` comes from `weather_api.precision`; `tz` comes from
`weather_api.timezone`. Weatherreporter does not call day-slice forecast or
discussion-subsection endpoints.
## Response Envelope
Each endpoint response must be JSON with a top-level `data` member:
```json
{
"data": {}
}
```
An absent `data` member is treated as a missing source. For ordinary sources,
`data: null` is also missing. The active-alert exception is listed above: its
explicit `null` payload represents an empty alert result.
Hourly forecast data must be present and contain at least one `period`; a
missing, malformed, or empty hourly product fails collection. The remaining
sources follow the configured missing-source policy. Under `error`, collection
fails; under `warn`, the source is omitted and an inspectable warning is
recorded; under `none`, the source is omitted without a warning. A per-source
policy overrides the default. See [Configuration](../config.md) for policy
settings and [Weather data internals](../internal/weather-data.md) for recorded
source metadata.
Malformed top-level JSON envelopes and HTTP failures are direct request errors.
Malformed `data` for an optional source follows its missing-source policy.
## Payload Fields Used
Weatherreporter decodes only the fields below; additional upstream fields are
ignored. Timestamps must be JSON values accepted by Go's `time.Time` decoder.
### Observations And Current Conditions
`/observations` uses `stationId`, `stationName`, `timestamp`, `conditionCode`,
`isDay`, `textDescription`, `temperatureC`, `temperatureF`, `dewpointC`,
`dewpointF`, `windSpeedKmh`, `windSpeedMph`, `windGustKmh`, `windGustMph`,
`windDirectionDegrees`, `barometricPressurePa`, `barometricPressureInHg`,
`visibilityMeters`, `visibilityMiles`, `relativeHumidityPercent`,
`apparentTemperatureC`, `apparentTemperatureF`, and `presentWeather`.
`/conditions/current` uses `conditionText`, `isDay`,
`relativeHumidityPercent`, `windDirectionDegrees`, `temperatureC`,
`temperatureF`, `apparentTemperatureC`, `apparentTemperatureF`, `dewpointC`,
`dewpointF`, `windSpeedKmh`, and `windSpeedMph`.
### Hourly And Narrative Forecasts
Both forecast endpoints use run-level `locationId`, `locationName`, `issuedAt`,
`updatedAt`, `product`, `latitude`, `longitude`, `elevationMeters`,
`elevationFeet`, and `periods`.
Each `periods` item uses `startTime`, `endTime`, `name`, `isDay`,
`conditionCode`, `textDescription`, `temperatureC`, `temperatureF`,
`temperatureCMin`, `temperatureFMin`, `temperatureCMax`, `temperatureFMax`,
`dewpointC`, `dewpointF`, `windSpeedKmh`, `windSpeedMph`, `windGustKmh`,
`windGustMph`, `windDirectionDegrees`, `barometricPressurePa`,
`barometricPressureInHg`, `visibilityMeters`, `visibilityMiles`,
`apparentTemperatureC`, `apparentTemperatureF`, `cloudCoverPercent`,
`probabilityOfPrecipitationPercent`, `precipitationAmountMm`,
`precipitationAmountIn`, `snowfallDepthMM`, `snowfallDepthIn`, `uvIndex`, and
`relativeHumidityPercent`.
### Alerts, Discussion, And Weather Story
`/alerts/active` uses the `asOf` timestamp and keeps each item in `alerts` as
an alert payload. Weatherreporter does not require a separate alert-item schema
at this integration boundary.
`/discussion` uses `officeId`, `officeName`, `product`, `issuedAt`,
`updatedAt`, `keyMessages`, and the `shortTerm` and `longTerm` sections. Each
section uses `qualifier`, `text`, and `issuedAt`.
`/weatherstories/latest` uses `officeId`, `startTime`, `endTime`, `updatedAt`,
`title`, `description`, `altText`, `priority`, `order`, and `downloadUrl`.
### SPC Convective Outlooks
`/outlooks/convective` uses run-level `locationId`, `locationName`, `asOf`,
`issuedAt`, `updatedAt`, `product`, `outlooks`, and `discussions`.
Each outlook uses `id`, `provider`, `product`, `day`, `outlookType`, `label`,
`labelText`, `forecaster`, `severityRank`, `validFrom`, `validTo`, `issuedAt`,
`expiresAt`, `sourceUrl`, `imageUrl`, `containsLocation`, and GeoJSON
`geometry`. Each discussion uses `day`, `headline`, `summary`, `discussion`,
and `updatedAt`.
## Timeouts, Retries, And Failures
The configured Weather API timeout applies to each warmup and source HTTP
attempt. Weatherreporter retries transient transport and response-read failures
and these response statuses: `408`, `429`, `500`, `502`, `503`, and `504`.
It does not retry other HTTP statuses, malformed envelopes, missing data, or
payload decoding failures. A canceled context also stops an in-progress retry
delay.
The adapter accepts response bodies up to 10 MiB and rejects larger bodies
before decoding. A non-2xx response reports its relative endpoint and status,
without including upstream response text. Request construction, response-limit,
read, and decode failures include endpoint context in their errors.
Retry counts and delays are adapter behavior rather than Weather API request
parameters. Do not depend on a particular attempt count when implementing the
service.