diff --git a/docs/decisions/0036-normalize-deeply-nested-json-apis.rst b/docs/decisions/0036-normalize-deeply-nested-json-apis.rst new file mode 100644 index 000000000000..b9b0c010c443 --- /dev/null +++ b/docs/decisions/0036-normalize-deeply-nested-json-apis.rst @@ -0,0 +1,95 @@ + +Reduce Deeply Nested JSON via Minimal/Flattened Views +===================================================== + +:Status: Proposed +:Date: 2026-04-08 +:Deciders: API Working Group + +Context +======= + +Some APIs return deeply nested JSON payloads (course structures, block trees, progress views). +This makes payloads hard to parse, increases response size, and slows clients and automated agents. + +Decision +======== + +1. Provide a "minimal" representation option for complex resources: + + * Query param example: ``?view=minimal`` or ``?fields=...``. + +2. Normalize/flatten overly nested structures where possible: + + * Prefer references/IDs with follow-up endpoints over embedding entire trees. + +3. Document response shapes in OpenAPI, including minimal vs full variants. + +Relevance in edx-platform +========================= + +* **Deeply nested payloads**: The course blocks API (``lms/djangoapps/course_api/blocks/views.py``) + returns a tree of blocks with ``root`` and ``blocks`` (dict keyed by usage ID), each block + containing ``id``, ``type``, ``display_name``, ``children``, ``student_view_data``, etc. + Full trees can be large and hard to parse. +* **Existing flexibility**: Blocks API already supports ``requested_fields`` and + ``block_types_filter`` to reduce payload; a ``view=minimal`` or ``fields=...`` + convention would align with this ADR. +* **Modulestore/OLX**: ``openedx/core/djangoapps/olx_rest_api/views.py`` returns + nested block OLX; providing a minimal (e.g. IDs + types only) view would help + clients that only need structure. + +Code example +============ + +**Query params for minimal representation:** + +.. code-block:: text + + GET /api/courses/v1/blocks//?depth=1&requested_fields=id,type,display_name + GET /api/course_structure/v1/?view=minimal + +**Response shape (minimal vs full):** + +.. code-block:: json + + // minimal (?view=minimal or ?fields=id,type,display_name,children) + { + "root": "block-v1:...", + "blocks": { + "block-v1:...": { "id": "...", "type": "chapter", "display_name": "Week 1", "children": ["..."] } + } + } + + // full: same structure but with student_view_data, completion, block_counts, etc. + +**Prefer IDs + follow-up over embedding:** + +.. code-block:: text + + GET /api/courses/v1/blocks/ → returns block IDs and types + GET /api/courses/v1/blocks// → returns full block when needed + +Consequences +============ + +* Pros + + * Improved performance and developer ergonomics. + * Easier integration for external services and AI agents. + +* Cons / Costs + + * Must maintain multiple representations; requires careful schema/versioning discipline. + +Implementation Notes +==================== + +* Start with endpoints called out in the standardization notes (course structure, contentstore index, + xblock, progress). +* Measure payload size reduction and client performance improvements. + +References +========== + +* “Hard-to-Parse Deeply Nested JSON” recommendation in the Open edX REST API standardization notes.