Skip to content

feat: add relational cross-links to individual resource endpoints#69

Open
AdityaAsopa wants to merge 3 commits intoisro:masterfrom
AdityaAsopa:feat/relational-cross-links
Open

feat: add relational cross-links to individual resource endpoints#69
AdityaAsopa wants to merge 3 commits intoisro:masterfrom
AdityaAsopa:feat/relational-cross-links

Conversation

@AdityaAsopa
Copy link

Summary

Adds a _links object to individual record endpoints (/api/spacecrafts/:id and /api/spacecraft_missions/:id) that points to related records in other collections.

What changes

GET /api/spacecrafts/:id now includes:

{
  "id": 10,
  "name": "INSAT-3B",
  ...
  "_links": {
    "self": "/api/spacecrafts/10",
    "mission": "/api/spacecraft_missions/5"
  }
}

GET /api/spacecraft_missions/:id now includes:

{
  "id": 5,
  "name": "INSAT-3B",
  ...
  "_links": {
    "self": "/api/spacecraft_missions/5",
    "spacecraft": "/api/spacecrafts/10"
  }
}

Design decisions

  • Only verifiable links — cross-links are resolved by exact case-insensitive name matching between the two datasets. All 64 mission records have a confirmed name match in the spacecrafts dataset.
  • No link when no match — if a name match isn't found, _links contains only self. No guessing.
  • Collection endpoints unchanged — links only appear on individual :id routes to avoid bloating collection responses.
  • _links convention — follows HAL-style hypermedia linking, a widely understood REST pattern.

Notes

This PR builds on feat/individual-id-endpoints (PR #67). The cross-link is only meaningful because both datasets now share consistent names from the normalization in PR #65.

Test plan

  • /api/spacecrafts/1 includes _links.self and _links.mission (Aryabhata has a mission entry)
  • /api/spacecraft_missions/1 includes _links.self and _links.spacecraft
  • A spacecraft with no mission entry has _links with only self
  • Collection endpoints (/api/spacecrafts, /api/spacecraft_missions) are unchanged

AdityaAsopa and others added 3 commits March 12, 2026 15:17
The spacecraft_missions data had deeply inconsistent schemas — mass appeared
as 'weight', 'lift-off_mass', 'spacecraft_mass', 'mass_at_lift-off' and
5 other variants; dates ranged from 'April 19, 1975' to '22 October 2008'
to '26-05-1999' across 15+ formats; KALPANA-1 had mission_life stored in
the 'mission' field as '7 Years'; and TES appeared as a duplicate entry.
spacecrafts.json had only id+name for 113 records. launchers.json had
only id for 81 records. customer_satellites.json mixed 'GERMANY' with
'Germany' and 'UK' with 'UNITED KINGDOM'.

This commit introduces scripts/normalize_data.py — an idempotent pipeline
that parses all date formats to ISO 8601, extracts numeric mass_kg and
power_watts from free-text fields (handling edge cases like '15 Sq.m Solar
Array generating 1360W'), classifies orbits (LEO/SSO/GEO/Lunar/Failed),
infers mission status from launch date + mission life, and normalizes
country names. The scraper was re-run against isro.gov.in and the fresh
data is merged with existing records — no data is lost, only enriched.

All 5 data files now have consistent, documented schemas. spacecrafts are
enriched with launch date, vehicle, orbit type, and status from missions.
Launchers are classified into 8 vehicle families. All API endpoints remain
backward-compatible — same URLs, same structure, just cleaner data.

API handlers: removed unused 'fs' imports, fixed misleading variable names
(customer_satellites.js loaded data into a var called 'launchers'), added
Content-Type: application/json headers, and sanitized error responses.
Root endpoint now returns a JSON directory of all available endpoints.
Adds /api/:resource/:id endpoints for all five collections:
- GET /api/spacecrafts/:id
- GET /api/launchers/:id
- GET /api/customer_satellites/:id
- GET /api/centres/:id
- GET /api/spacecraft_missions/:id

Returns the matching record directly (not wrapped), 404 if not found,
400 if ID is not a valid integer. No new data added — reads directly
from existing normalized JSON files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/api/spacecrafts/:id now includes a _links object:
  - _links.self: canonical URL for the spacecraft
  - _links.mission: URL to the matching spacecraft_missions record (when available)

/api/spacecraft_missions/:id now includes a _links object:
  - _links.self: canonical URL for the mission
  - _links.spacecraft: URL to the matching spacecrafts record (when available)

Cross-links are resolved by case-insensitive name matching between the
two datasets. All 64 mission records have a matching spacecraft entry.
No link is added when no match is found — no guessing.

Collection endpoints and other individual endpoints are unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant