Skip to content

[API] Course Index #39066

Open
Open

Description

@FuaadZam

Functional Area: Course Index

Endpoints under this functional area:

Module API Version Resource / Endpoint HTTP Method Description
Course Outline v1 /contentstore/v1/course_index/{course_id} GET Retrieves the course outline/index for a given course ID. Returns JSON including course release date, course structure, deprecated blocks info, proctoring URLs, discussions links, initial state of expanded locators, initial user clipboard, LMS link, reindex link, notification IDs, and custom relative dates status. Optional query parameter show can set initial expanded state of the outline. Supports AI tools in visualizing course hierarchy, analyzing course structure, or dynamically rendering content navigation.

Activity

  1. added theissue type on Sep 2, 2026
  2. taimoor-ahmed-1 commented on Oct 14, 2026

    @taimoor-ahmed-1
    Contributor

    Standardization PR open: #39229

    PR: #39229 — feat: serve the course outline from authoring v2
    State: open

    What this does

    This PR standardizes the Course Index functional area (#39066, umbrella #38137) as a new resource, GET /api/authoring/v2/courses/{course_key}/outline/, following the API standardization ADRs docs/decisions/0025 to 0038 and OEP-69. GET /api/contentstore/v1/course_index/{course_id} stays mounted and unchanged, and is marked deprecated.

    ADRs applied

    10 of 16 decisions applied on this pass; every one left open carries its reason.

    • 0025 serializers
    • 0026 permissions
    • 0027 schema / docs
    • 0028 viewsets
    • 0030 GET idempotence
    • 0034 authentication
    • 0036 nested JSON
    • 0037 versioning
    • 0038 URL structure
    • OEP-69 conventions
    • 0029 errors — envelope on every 400/401/403/404 this view raises, and no input crashes it. Open and pinned by tests that flip when fixed: (1) a malformed or slash-form course key gets the routing-level HTML 404 (no authoring catch-all yet); (2) 405 and 406 are typed internal until edx-drf-extensions catalogues them.
    • 0031 merged endpoints — n/a: a single read operation
    • 0032 pagination — n/a: one tree-shaped resource; depth is capped instead (ADR 0036 Pattern A)
    • 0033 filtering — n/a: no list; the query parameters choose a representation and a subtree, and are serializer-validated
    • 0035 MFE config — n/a: authenticated and per-course, not configuration
    • OEP-66 queryset scoping — n/a: not a list endpoint

    The evidence for each tick is the compliance matrix in the PR body; nothing is ticked without a named test or gate line.

    Backward compatibility

    • Versions gate: PASS. v1 course_index.py changes only in docstring lines; with docstrings stripped, its AST equals master. v2/authoring_urls.py gains one route. Protected, untouched: utils.py, views/course.py, xblock_storage_handlers/view_handlers.py (the shared outline builder), rest_api/serializers/common.py, the content-staging API and models, view_utils.py, the authz decorators, the CourseOverview model, docs/cms-openapi.yaml.
    • URLs gate: PASS. One route added; every base route still resolves.
    • Schema gate: PASS, 0 breaking. Two additions: the v2 GET, and the v1 GET newly deprecated: true. Warnings:
      • two new ones: the platform-default authenticator warnings that every default-auth view emits;
      • three that look new: ContainerChildrenView's existing warnings, moved by the docstring lines.
    • v1 tests: untouched and green.
    • Parity (?view=full vs v1, through the test client). The comparison is typed, keeps empty containers, and fails on a difference that is not declared or a declared one that does not occur. Declared differences:
      • initial_user_clipboard: always absent in v2.
      • For courses whose blocks have pre-1900 start dates: course_release_date, start, release_date, released_to_students and visibility_state (v1 repairs these dates on read and reports "Set Date"/unscheduled; v2 reports them as stored).
    • course_structure stays a free-form object, as in v1. The shared create_xblock_info builds it, and OVERRIDE_CREATE_XBLOCK_INFO plugins can extend it. Its node keys are documented in the schema. OutlineFullViewNodeKeysTest pins the key set per block role, so a change to the shared builder fails loudly.

    Gates

    versions   PASS  v1 docstring-only; 2 allowed files, 4 new v2 modules; protected files untouched
    hygiene    PASS  0 FAIL, 0 WARN
    schema     PASS  0 BREAKING; v2 GET added, v1 GET newly deprecated
    urls       PASS  0 FAIL, 0 WARN; one route added
    old-tests  PASS  37 passed, 7 skipped (v1 course index, unmodified)
    tests      PASS  340 passed (v2 outline, textbooks, video settings; certificates; CMS schema hooks)
    

    Deprecations

    GET /api/contentstore/v1/course_index/{course_id} is deprecated: true in the CMS schema, and its docstrings name the v2 successor. No runtime header (frozen route). The DEPR record is an entry on #39128: this comment. Folding this entry, and the ones for #39102, #39186 and #39227, into the issue body is pending. Window, per #39128: the marking ships in the next named release after Verawood, and v1 stays mounted until one named release after that.

    Follow-ups

    • Authoring v2: a JSON catch-all for malformed keys.
    • edx-drf-extensions: catalogue 405 and 406.
    • content_staging: the clipboard GET can save a CourseOverview row.
    • Pre-1900 start dates: a non-GET home for the date repair.
    • frontend-app-authoring: migrate the outline and competency-management screens to v2 ?view=full.

    🤖 Generated with Claude Code

    Review on the PR, please — this issue stays open until it merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions