Files
weatherapi/docs/internal/presenters.md

5.1 KiB

Presenters and Templates

This document describes payload shaping in internal/adapters/inbound/httpapi/presenter and its relationship to text templates. Public response fields are documented in docs/api.md.

Purpose

Presenters translate repository/application read models into response-ready payloads. They own unit conversion, numeric rounding, timezone conversion, optional field preservation, and copy semantics.

Inputs and Outputs

Inputs:

  • weatherfeeder model values returned by the repository;
  • app.CurrentConditions values returned by the application service;
  • requested unit mode;
  • requested precision;
  • optional timezone location.

Outputs:

  • JSON/XML/text-ready payload structs or canonical model copies;
  • nil payloads for nil inputs.

Boundaries

Presenters may:

  • convert metric values to US-customary response fields;
  • round numeric values that are presentation values;
  • convert timestamps to a requested timezone;
  • copy slices and pointers before changing presentation values;
  • add template-only helper fields when they are not serialized.

Presenters must not:

  • execute SQL;
  • call services or repositories;
  • parse HTTP query parameters;
  • load templates;
  • change canonical repository models in place.

Config Fields Used

Presenters do not read config directly. They receive unit, precision, and timezone selections from HTTP binders. Text output depends indirectly on templates.base_dir because feedapi loads templates from that configured directory.

External Adapters Used

  • weatherfeeder/model for canonical weather payloads.
  • weatherfeeder/standards for current-condition text from WMO codes.
  • internal/app for the current-conditions read model.
  • Feedapi templates indirectly consume presenter output during text rendering.

State

Presenters are stateless. Helper functions allocate copied values and return new payloads for each request.

Unit Conversion

Metric mode generally returns weatherfeeder canonical model shapes or metric-named fields. US mode uses explicit US response structs for observations and forecasts and US-specific fields in current conditions.

Conversion constants live in constants.go:

  • Celsius to Fahrenheit;
  • kilometers per hour to miles per hour;
  • meters to miles or feet;
  • pascals to inches of mercury;
  • millimeters to inches.

Non-unit fields such as percentages, directions, text, IDs, and ordering values keep their existing values.

Precision

roundedPtr and roundFloat round numeric presentation values. Precision 0 rounds to whole numbers. Positive precision uses powers of ten. Nil numeric pointers remain nil.

Latitude and longitude are copied but not rounded by forecast presenters.

Timezone Conversion

inLocationTime and inLocationTimePtr convert timestamps only when a timezone is supplied. Without a timezone, timestamps are preserved as returned by the repository.

Timezone conversion is applied by forecast, discussion, weather story, and outlook presenters. Observations and current conditions do not currently receive timezone input from their routes.

Optional Fields and Copy Semantics

Presenter helpers copy pointer values before changing them. Slices are copied before inclusion where needed. This preserves nil/omitempty behavior and avoids mutating repository-returned values.

Nil input payloads return nil. Endpoint handlers wrap those nil payloads in a response envelope so renderers can produce data: null.

Endpoint Families

  • Observations: metric copy or US response shape, including present-weather slice copy.
  • Current conditions: single response shape with either metric or US unit fields populated, plus a template-only day/night text helper.
  • Alerts: pass-through of canonical alert runs, with nil preserved.
  • Forecasts: metric copy or US response shape, period copy, unit conversion, precision, and timezone conversion.
  • Discussions: full or focused payload shapes, section copy, key-message copy, timezone conversion.
  • Weather stories: run/story copy and timezone conversion.
  • Convective outlooks: canonical model copy, pointer and geometry copy, and timezone conversion. units is accepted by routes but ignored by the presenter because outlook fields are not unit-bearing.

Templates

Text templates consume the same envelope data produced by presenters. Template files live under templates/ and are loaded by feedapi from templates.base_dir.

Presenter changes can break text output even when JSON and XML still compile. Check template field references before renaming or removing presenter fields.

Tests to Inspect Before Changing

  • internal/adapters/inbound/httpapi/presenter/payload_test.go
  • internal/adapters/inbound/httpapi/endpoints_test.go for rendered text and envelope behavior
  • affected template files under templates/

Invariants

  • Keep unit conversion and rounding out of handlers and repositories.
  • Preserve nil pointer and optional field behavior.
  • Copy before converting, rounding, or timezone-shifting values.
  • Keep text-template helper fields out of JSON/XML when they are not API fields.
  • Update docs/api.md and templates when payload shape changes.