# weatherapi HTTP API This is the canonical public HTTP contract for `weatherapi`. The service is a read-only API over the latest weather records available in the configured weatherfeeder-populated Postgres database. ## Base URL All paths are relative to the deployment root: ```text http://localhost:8080 ``` Use your deployment host in production. ## Authentication `weatherapi` does not implement authentication or authorization. Put access control in front of the service when a deployment requires it. ## Response Envelope Successful JSON and XML responses use a top-level envelope: ```json { "data": {} } ``` When no latest/current resource exists, the request still succeeds and returns `data: null`. Text responses are rendered from endpoint-specific templates. When the payload is missing, the templates return a short no-data message. ## Formats Every implemented endpoint can produce: | Format | Media type | | --- | --- | | `json` | `application/json` | | `xml` | `application/xml` | | `text` | `text/plain` | Format selection is: 1. `format` query parameter; 2. `Accept` header; 3. configured `server.default_format`. `format` values are case-insensitive. Unsupported formats return `406 Not Acceptable` with an error envelope. ## Shared Query Rules Unknown query parameters are rejected with `400 Bad Request`. | Parameter | Values | Default | Supported on | | --- | --- | --- | --- | | `format` | `json`, `xml`, `text` | configured default | all endpoints | | `units` | `metric`, `us` | `metric` | all endpoints | | `precision` | integer `0` through `2` | `0` | observations, current conditions, forecasts | | `tz` or `TZ` | timezone selector | UTC/no conversion | forecasts, discussions, weather stories | `units`, `format`, and `precision` values are normalized case-insensitively where applicable. `units=metric` returns metric field names; `units=us` returns US-customary field names for unit-bearing payloads. Alerts, discussions, and weather stories accept `units` but their current payload fields are not materially changed by it. `precision` controls numeric rounding. The default `0` rounds to whole numbers. `precision` is rejected on alerts, discussions, and weather stories. Timezone selectors accepted by `tz` / `TZ`: - IANA timezone names such as `America/Chicago`; - common US abbreviations such as `CDT`, `CST`, `EDT`, `EST`, `MDT`, `MST`, `PDT`, and `PST`; - UTC offsets in `+H`, `+HH`, `+HH:MM`, `-H`, `-HH`, or `-HH:MM` form, bounded to `-14:00` through `+14:00`; - aliases `Chicago` and `Stl`, both mapped to `America/Chicago`. If both `tz` and `TZ` are provided, their values must match case-insensitively. Timezone conversion affects rendered timestamps and forecast `/today` and `/tomorrow` day-slice filtering. Without a timezone parameter, day-slice routes use UTC. ## Errors API errors use a stable error envelope: ```json { "error": { "code": "invalid_parameter", "message": "..." } } ``` Implemented API error statuses: | Status | Code | Cause | | --- | --- | --- | | `400 Bad Request` | `invalid_parameter` | unknown query parameter, invalid parameter value, invalid timezone, conflicting `tz` / `TZ`, or unsupported parameter on a route | | `406 Not Acceptable` | `unsupported_format` | requested response format is not supported by the endpoint/renderers | Unhandled service or database errors are returned as server errors by the runtime. ## Behavior Not Implemented `weatherapi` does not implement pagination, cache-control headers, rate-limit headers, idempotency keys, retries, writes, or historical browsing outside the implemented latest-resource and forecast day-slice routes. ## Endpoints ### Observations ```http GET /observations ``` Returns the latest weather observation. Query parameters: `format`, `units`, `precision`. Metric `data` fields: | Field | Type | Notes | | --- | --- | --- | | `stationId`, `stationName` | string | optional | | `timestamp` | RFC3339 datetime | required when `data` is not null | | `conditionCode` | integer | WMO weather code | | `isDay` | boolean | optional | | `textDescription` | string | optional | | `temperatureC`, `dewpointC`, `apparentTemperatureC` | number | optional | | `windDirectionDegrees`, `windSpeedKmh`, `windGustKmh` | number | optional | | `barometricPressurePa`, `visibilityMeters` | number | optional | | `relativeHumidityPercent` | number | optional | | `presentWeather` | array | optional | US mode replaces unit-bearing fields with `temperatureF`, `dewpointF`, `apparentTemperatureF`, `windSpeedMph`, `windGustMph`, `barometricPressureInHg`, and `visibilityMiles`. Direction and percentage fields keep the same names. Example: ```http GET /observations?units=us&precision=1 ``` ### Current Conditions ```http GET /conditions/current ``` Returns current conditions aggregated from recent `observations` rows. The implemented observation window is 30 minutes. Query parameters: `format`, `units`, `precision`. Common `data` fields: | Field | Type | Notes | | --- | --- | --- | | `conditionText` | string | optional text derived from WMO code and day/night flag | | `isDay` | boolean | optional | | `relativeHumidityPercent` | number | optional | | `windDirectionDegrees` | number | optional | Metric fields: `temperatureC`, `apparentTemperatureC`, `dewpointC`, `windSpeedKmh`. US fields: `temperatureF`, `apparentTemperatureF`, `dewpointF`, `windSpeedMph`. Example: ```http GET /conditions/current?format=json&precision=0 ``` ### Active Alerts ```http GET /alerts/active ``` Returns the latest active-alert snapshot. Query parameters: `format`, `units`. Run `data` fields: | Field | Type | Notes | | --- | --- | --- | | `locationId`, `locationName` | string | optional | | `asOf` | RFC3339 datetime | required when `data` is not null | | `latitude`, `longitude` | number | optional | | `alerts` | array | active alerts, possibly empty | Alert fields include `id`, `event`, `headline`, `severity`, `urgency`, `certainty`, `status`, `messageType`, `category`, `response`, `description`, `instruction`, `sent`, `effective`, `onset`, `expires`, `areaDescription`, `senderName`, and `references`. Most alert fields are optional except `id` when an alert item is present. Reference fields are `id`, `identifier`, `sender`, and `sent`. Example: ```http GET /alerts/active?format=text ``` ### Forecasts ```http GET /forecast/hourly GET /forecast/hourly/today GET /forecast/hourly/tomorrow GET /forecast/narrative GET /forecast/narrative/today GET /forecast/narrative/tomorrow ``` Returns the latest hourly or narrative forecast run. `/today` and `/tomorrow` return a copy of the latest run with `periods` filtered by each period's `startTime` in the resolved timezone. If no periods match, `data` remains an object and `periods` is an empty array. Query parameters: `format`, `units`, `precision`, `tz` / `TZ`. Run `data` fields: | Field | Type | Notes | | --- | --- | --- | | `locationId`, `locationName` | string | optional | | `issuedAt` | RFC3339 datetime | required when `data` is not null | | `updatedAt` | RFC3339 datetime | optional | | `product` | string | `hourly` or `narrative` for implemented routes | | `latitude`, `longitude` | number | optional | | `elevationMeters` or `elevationFeet` | number | optional, depends on `units` | | `periods` | array | ordered forecast periods | Metric period fields: `startTime`, `endTime`, `name`, `isDay`, `conditionCode`, `textDescription`, `temperatureC`, `temperatureCMin`, `temperatureCMax`, `dewpointC`, `relativeHumidityPercent`, `windDirectionDegrees`, `windSpeedKmh`, `windGustKmh`, `barometricPressurePa`, `visibilityMeters`, `apparentTemperatureC`, `cloudCoverPercent`, `probabilityOfPrecipitationPercent`, `precipitationAmountMm`, `snowfallDepthMm`, and `uvIndex`. US mode uses the same non-unit fields and replaces unit-bearing fields with `temperatureF`, `temperatureFMin`, `temperatureFMax`, `dewpointF`, `windSpeedMph`, `windGustMph`, `barometricPressureInHg`, `visibilityMiles`, `apparentTemperatureF`, `precipitationAmountIn`, `snowfallDepthIn`, and `elevationFeet` at run level. `startTime` and `endTime` are required for each period. Other period fields are optional, including `conditionCode`; narrative forecasts may omit it. Examples: ```http GET /forecast/hourly?units=us&precision=1&TZ=-5 GET /forecast/narrative/tomorrow?format=text&tz=Chicago ``` ### Forecast Discussions ```http GET /discussion GET /discussion/key-messages GET /discussion/short-term GET /discussion/long-term ``` Returns the latest forecast discussion or a focused subresource. Query parameters: `format`, `units`, `tz` / `TZ`. Full discussion `data` fields: | Field | Type | Notes | | --- | --- | --- | | `officeId`, `officeName` | string | optional | | `product` | string | currently `afd` from weatherfeeder data | | `issuedAt` | RFC3339 datetime | required when `data` is not null | | `updatedAt` | RFC3339 datetime | optional | | `keyMessages` | array of strings | optional | | `shortTerm`, `longTerm` | object | optional section objects | Discussion section fields are `qualifier`, `issuedAt`, and `text`, all optional. Subresources return the same metadata plus only their focused field: `keyMessages`, `shortTerm`, or `longTerm`. Example: ```http GET /discussion/short-term?format=text&tz=CDT ``` ### Weather Stories ```http GET /weatherstories GET /weatherstories/latest ``` `/weatherstories` returns the latest weather-story run and its ordered stories. `/weatherstories/latest` returns the latest individual story. Query parameters: `format`, `units`, `tz` / `TZ`. Run `data` fields: | Field | Type | Notes | | --- | --- | --- | | `officeId` | string | optional | | `asOf` | RFC3339 datetime | required when `data` is not null | | `stories` | array | ordered story objects | Story fields: | Field | Type | Notes | | --- | --- | --- | | `officeId` | string | optional | | `startTime`, `endTime`, `updatedAt` | RFC3339 datetime | required when a story is present | | `title`, `description`, `altText`, `downloadUrl` | string | optional | | `priority` | boolean | required when a story is present | | `order` | integer | required when a story is present | Examples: ```http GET /weatherstories?tz=America/Chicago GET /weatherstories/latest?format=xml ``` ## Copyable Requests See [`examples/requests.http`](../examples/requests.http) for a compact set of requests covering the implemented endpoint families.