Bundling First-Screen Values into One Response: home-summary
I put parking, outing, forecast, and source status into one response so the app and widgets start from the same values
Hangangjari’s first screen shows several kinds of data at the same time. Parking lots, current values, forecasts, crowding, events, facility summaries, directions candidates, and source checks all meet on one screen.
At first it is tempting to let the client call several responses and compose them. But real screens drift quickly.
The parking section may have just refreshed while the event section is stale. The forecast may be looking at a different horizon. A widget may receive only some values and create a completely different impression.
So Hangangjari lets the server bundle the values needed for the first screen. This was not only about making client code easier.
The first screen is the first few seconds in which users judge the app. Those few seconds should not contain values speaking from different times.
The first screen receives the needed values at once
home-summary is Hangangjari’s first-screen response. The goal is: “for one park, receive the first values that the app and widgets will see in one request.”
flowchart LR API["Per-park first-screen response"] --> Park["Park"] API --> Parking["Parking aggregate<br/>lot status"] API --> Forecast["Parking forecast<br/>park crowd forecast"] API --> Outing["Outing summary<br/>signals / facility groups / directions"] API --> Freshness["Refresh state<br/>source checks"]
Without this response, the app would need to fetch lot lists, current values, forecast overview, outing overview, and source checks separately. That creates problems on the first screen.
- Success and failure can diverge across calls.
- Part of the screen can remain on a previous park.
- Widgets cannot comfortably handle multiple network calls.
- Cache and freshness checks become more complex.
- iOS decoding needs a wider defensive surface when the API changes.
When the server bundles the first-screen values, those problems shrink into one response.
Of course, home-summary also needs care as it grows. If it becomes a response that includes everything, it becomes slow and fragile again.
So the rule for inclusion is: “is it immediately needed on the first screen?” Long lists or raw payloads needed only on detail screens do not belong here.
The response is split into four bundles
The iOS value is divided into four large parts.
| Field | Role |
|---|---|
park | Confirms which park this summary is for |
parking | Parking aggregate, recommended lot, lots, and statuses |
forecast | Forecast horizon and parking/park crowd overview |
outing | General-screen signals, facility groups, directions, and source checks |
HomeSummary is not only for the app screen. The existing parking screen can use the parking overview from it, and the general screen can reuse compact data.
flowchart TB HomeSummary --> ParkingOverview["ParkingOverview value"] HomeSummary --> OutingOverview["Partial OutingOverview value"] HomeSummary --> WidgetParking["Parking widget snapshot"] HomeSummary --> WidgetGeneral["General widget snapshot"]
The client splits the value bundled by the server by screen.
This reduced duplicate calls. Parking overview, general park summary, and widget snapshots all start from the same response, so screen transitions are less likely to replace a value the user just saw with a value from another time.
Already installed apps still need to read the new response
iOS apps update more slowly than servers. There will always be a period when already installed apps read a new server payload. In home-summary, I first considered how older apps could still read the response before adding new values.
The rules are:
- Do not casually remove existing required fields.
- Start new values as optional fields or nested-object additions.
- Enums must define behavior for unknown values.
- Do not change the meaning of date and freshness fields.
- If the park ID differs from the requested value, do not trust the payload.
The widget loader follows the same approach. Even if it receives home-summary from the network, it treats the data as empty if the park ID does not match the request. A small guard like this prevents cache contamination.
Compatibility sounds boring, but it is very real for a shipped iOS app. The server may already be sending new fields while users are on older apps. An API that cannot survive this period becomes less stable as values are added.
iOS splits the first-screen response into cache
iOS stores the received HomeSummary in SwiftData. It does not only store one payload. It also reflects the inner park, lots, statuses, and forecast overview into their respective caches.
sequenceDiagram
autonumber
participant Store as App state store
participant Repo as Parking repository
participant API as Hangangjari API
participant Cache as SwiftData cache
Store->>Repo: Check stored first-screen value
alt Cache is fresh
Repo-->>Store: Return cached first-screen value
else Stale or missing
Repo->>API: Request first-screen response
API-->>Repo: Return first-screen response
Repo->>Cache: Store first-screen value
Repo->>Cache: Update park/parking/status/forecast caches
Repo-->>Store: Return new first-screen value
end
This lets the first screen and detail screens start from the same response. When the user enters parking detail, the value just received is not thrown away.
Server cache also does not hide stale values
The server keeps both a fast-response cache and a last-success response cache for home-summary. When a rebuild succeeds, both caches are updated. If rebuilding fails, the last successful response can be returned.
HTTP responses also receive Cache-Control: private and ETag. This is not about keeping the response in a public cache for a long time. It lets the same app instance receive 304 for repeated first-screen requests in a short period.
Again, the thing not to hide is staleness. Even when returning a stale backup, the freshness state and source-check results in the payload must remain intact.
I aligned the first few seconds to the same value
The first screen was simpler as one response than as a composition of several calls. The server-bundled first-screen value became the shared starting point for app screens, widgets, and cache.
iOS decoding stability depended less on “adding new fields” and more on “preserving existing meaning.” Validating the requested park against the response park reduces cache contamination, and stale cache remains a way to show the last confirmed value rather than to hide an outage.
The biggest effect of home-summary was not only reducing call count. It was making the app, widgets, and cache see the same first value.
To stabilize the first few seconds a user sees, the server and client have to say the same thing.
Share
No comments yet. You can leave the first one.
Pending review