Multi-Source Orbit Ingest for APIs¶
Problem¶
A service endpoint needs one stable contract but must accept object inputs from multiple upstream sources (SBDB, Scout, NEOCC, Horizons).
Implementation Options and Tradeoffs¶
Source-specific endpoints: Simple for implementation, but duplicates validation and downstream logic.
One endpoint with source routing: Cleaner operational model and cache strategy, with slightly more source-specific branching.
Runnable Example¶
from adam_core.orbits import Orbits
from adam_core.orbits.query import query_horizons, query_neocc, query_sbdb, query_scout
from adam_core.time import Timestamp
def load_orbits(source: str, object_ids: list[str]) -> Orbits:
if source == "sbdb":
return query_sbdb(object_ids)
if source == "scout":
# scout returns variants; collapse for deterministic downstream service logic
return query_scout(object_ids).collapse_by_object_id()
if source == "neocc":
return query_neocc(object_ids)
if source == "horizons":
t0 = Timestamp.from_mjd([60200.0], scale="tdb")
return query_horizons(object_ids, t0)
raise ValueError(f"Unsupported source: {source}")
When to Use This Pattern¶
Use this for public or internal APIs where clients choose data source at request
time but downstream pipelines require one normalized Orbits table type.