Repository navigation
Consolidate the 7 MapViewPage.vue resultTime=latest fallback call sites into a single helper #47
Description
Summary
demo/src/pages/MapViewPage.vue (in this repo) currently contains seven copy-pasted instances of the same 5–7 line "request latest observation; if empty, fall back to plain limit=1" pattern. Consolidate those into a single per-page (or per-module) helper so the pattern is implemented and tested in one place. This is purely a consumer-side ergonomic cleanup; no library change is required.
Context — why this lives here, not in the library
The fallback pattern was introduced because the OS4CSAPI/connected-systems-go server silently ignores the resultTime=latest query parameter (and, as documented in the upstream client's references catalog, the broader temporal-parameter family). Server-side root cause is tracked at connected-systems-go#11.
The TypeScript client (OS4CSAPI/ogc-client-CSAPI_2) considered shipping a built-in compatibility shim for this pattern in ogc-client-CSAPI_2#168, then closed that issue wontfix after Phase 8 triage. Reasons for the rejection (summary; full text in that issue's status banner):
- Library is already spec-correct — fault lies entirely with the Go server.
- A shim targeting only
latestwould be selective; the server ignores the entire temporal-parameter family, not just one keyword. - The shim is not transparent — consumers must still know which server class they target (the fallback URL is unsafe against SensorHub due to ascending default sort).
- Adding a method whose deprecation is already scheduled at filing time is an anti-pattern.
- N=1 consumer ergonomic problems belong in the consumer's repo.
This issue is the consequence of that last point: the ergonomic cleanup is worth doing, just here rather than in the library.
Affected sites in MapViewPage.vue
Per ogc-client-CSAPI_2#168, the seven sites are:
buildSystemLocationCache()Phase C — observation-derived system locationsrefreshLocalizerOverlay()— localizer position fetchloadObservationTracks()— orbit/track latest-time anchorrefreshLivePositions()— live position update cycleMapViewPage.vue— observation fetch path A (map rendering pipeline)MapViewPage.vue— observation fetch path B (map rendering pipeline)- Bearing-line refresh cycle
(Line numbers will need to be verified by whoever picks this up.)
Each site currently looks roughly like:
const url = builder.getDataStreamObservations(dsId, { resultTime: 'latest', limit: 1 });
let obsRes = await apiFetch(url, { headers: { Accept: 'application/om+json' } });
if (obsRes.ok && obsRes.data && !(obsRes.data.items?.[0] || obsRes.data[0])) {
const fallbackUrl = builder.getDataStreamObservations(dsId, { limit: 1 });
obsRes = await apiFetch(fallbackUrl, { headers: { Accept: 'application/om+json' } });
}Recommended direction
Implementation is the maintainer's call. The shape below is one option; the goal is one place where this lives, not a specific API.
Add a small page-local helper, e.g. in MapViewPage.vue's <script setup> block or a sibling useLatestObservation.ts composable:
async function fetchLatestObservation(
builder: CSAPIQueryBuilder,
datastreamId: string,
apiFetch: ApiFetch,
): Promise<Observation | null> {
const headers = { Accept: 'application/om+json' };
const primary = builder.getDataStreamObservations(datastreamId, {
resultTime: 'latest',
limit: 1,
});
let res = await apiFetch(primary, { headers });
const items = res.data?.items ?? res.data ?? [];
if (res.ok && items.length === 0) {
// Server may silently ignore resultTime=latest (e.g. connected-systems-go);
// fall back to plain limit=1 — relies on server's default sort being
// descending (true for Go; NOT TRUE for SensorHub — see notes below).
const fallback = builder.getDataStreamObservations(datastreamId, { limit: 1 });
res = await apiFetch(fallback, { headers });
}
const first = (res.data?.items ?? res.data ?? [])[0] ?? null;
return first;
}Then each of the seven sites becomes a single call. Caveats to capture in the JSDoc on this helper:
- The fallback path only works against servers whose default sort is descending by
resultTime. Currently true forconnected-systems-go; not true for OSH/SensorHub (ascending default). If the Explorer ever needs to support targeting SensorHub through the same code path, the helper needs a sort hint (or the fallback needs to be disabled when the server class is known to sort ascending). - This helper is server-quirk compensation, not idiomatic CSAPI usage. When
connected-systems-go#11ships, the helper can be simplified to just the primary path (and the fallback removed).
Out of scope
- ❌ Modifying the upstream library (
ogc-client-CSAPI_2) — see#168for the closure rationale. - ❌ Re-implementing the workaround for other temporal parameters (
phenomenonTime,issueTime, etc.) — onlyresultTime=latestis currently used byMapViewPage.vue. If/when other temporal parameters are needed, generalize then; don't pre-build. - ❌ Adding a "server class" detection mechanism — the helper documents the constraint in JSDoc; runtime detection is over-engineering for the Explorer's current single-target deployment.
Acceptance criteria
- One helper function (or composable) exists, with JSDoc documenting the server-quirk rationale and the SensorHub-incompatibility caveat.
- All seven sites in
MapViewPage.vuecall the helper. - Behavior is identical to the current copy-pasted blocks (no regression).
- When
connected-systems-go#11ships and the Go server starts honoringresultTime=latest, the helper's fallback branch should become a no-op (i.e. the primary URL returns the data and the helper returns from the first apiFetch). This should be verified by re-running the Explorer against the fixed server when available.
References
| # | Source | Role |
|---|---|---|
| 1 | OS4CSAPI/ogc-client-CSAPI_2#168 |
Library-side decision to close wontfix and push this work into the consumer repo |
| 2 | OS4CSAPI/connected-systems-go#11 |
Server-side root cause; deprecation trigger for the helper |
| 3 | docs/research/references.md — Known Server Conformance Gaps |
Catalog of empirically observed Go server gaps; "Gap 1" entry covers this exact behavior |
| 4 | OGC 23-002r0 §13.3.2 /req/advanced-filtering/obs-by-resulttime statement D |
Spec the server should honor and currently doesn't |
Activity
docs(phase-8): add P8-contribution-goal-and-definition.md (trio doc 1…