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
latest would 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 locations
refreshLocalizerOverlay() — localizer position fetch
loadObservationTracks() — orbit/track latest-time anchor
refreshLivePositions() — live position update cycle
MapViewPage.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 for connected-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#11 ships, 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 #168 for the closure rationale.
- ❌ Re-implementing the workaround for other temporal parameters (
phenomenonTime, issueTime, etc.) — only resultTime=latest is currently used by MapViewPage.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
References
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 plainlimit=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-goserver silently ignores theresultTime=latestquery parameter (and, as documented in the upstream client's references catalog, the broader temporal-parameter family). Server-side root cause is tracked atconnected-systems-go#11.The TypeScript client (
OS4CSAPI/ogc-client-CSAPI_2) considered shipping a built-in compatibility shim for this pattern inogc-client-CSAPI_2#168, then closed that issuewontfixafter Phase 8 triage. Reasons for the rejection (summary; full text in that issue's status banner):latestwould be selective; the server ignores the entire temporal-parameter family, not just one keyword.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.vuePer
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)(Line numbers will need to be verified by whoever picks this up.)
Each site currently looks roughly like:
Recommended direction
Add a small page-local helper, e.g. in
MapViewPage.vue's<script setup>block or a siblinguseLatestObservation.tscomposable:Then each of the seven sites becomes a single call. Caveats to capture in the JSDoc on this helper:
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).connected-systems-go#11ships, the helper can be simplified to just the primary path (and the fallback removed).Out of scope
ogc-client-CSAPI_2) — see#168for the closure rationale.phenomenonTime,issueTime, etc.) — onlyresultTime=latestis currently used byMapViewPage.vue. If/when other temporal parameters are needed, generalize then; don't pre-build.Acceptance criteria
MapViewPage.vuecall the helper.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
OS4CSAPI/ogc-client-CSAPI_2#168wontfixand push this work into the consumer repoOS4CSAPI/connected-systems-go#11docs/research/references.md— Known Server Conformance Gaps/req/advanced-filtering/obs-by-resulttimestatement D