You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Retrieves all libraries on the home page. Supports optional query parameters: org (filter by organization) and is_migrated (boolean, true or false to filter legacy libraries by migration status). Returns display name, library key, URL, edit permissions, and migration info. Useful for AI systems or external tools managing library content or migration tracking.
PR:#39238 — feat: apply FC-0118 ADRs to legacy libraries API State: open
What this does
Standardizes the Libraries functional area (#39069, part of #38137). This area has one operation: "list the legacy (v1, modulestore) libraries the requester can read". Today it is served at three addresses across two versions; this PR adds its v4 at /api/authoring/v4/legacy_libraries/.
New addresses
GET /api/authoring/v4/legacy_libraries/ (supersedes GET /api/contentstore/v1/home/libraries, GET /api/contentstore/v3/home/libraries/ and GET /api/authoring/v3/home/libraries/, now deprecated: true in the CMS schema)
ADRs applied
10 of 16 decisions applied on this pass; every one left open carries its reason.
OEP-66 queryset scoping — mechanism n/a: the data path is the modulestore, with no get_queryset() for ScopedQuerysetMixin to wrap; the three layers are implemented in the service and tested (see the matrix)
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
Schema: 0 breaking changes (69 → 70 paths). URLs: every base route keeps its pattern, name and view (2162 → 2163). The 24 legacy tests pass unmodified; v4 responses match v3 field for field (parity test, 20 rows).
GET /api/contentstore/v1/home/libraries, GET /api/contentstore/v3/home/libraries/ and GET /api/authoring/v3/home/libraries/ are superseded by GET /api/authoring/v4/legacy_libraries/. They are marked deprecated: true in the published CMS schema; the v3 contentstore address was already marked through its /api/contentstore/v3/home/ prefix. The superseded views are unchanged: no response header, and no deprecation notes in code. /api/authoring/v3/home/ and /api/authoring/v3/home/courses/ remain current.
Tracked on the FC-0118 umbrella DEPR ticket, #39128, which removes them one named release after the release this ships in. This area's entry: #39128 (comment)
Migration notes for callers:
The list is paginated: {count, num_pages, current_page, start, next, previous, results}, 10 per page by default, page_size up to 100. Each item in results has the fields of an item in the old libraries array, under the same names.
Items are ordered by display name (case-insensitive), then library key.
org now filters by the organization in the library key, as an exact, case-sensitive match; v1 and v3 documented it but ignored it. is_migrated behaves as before. An empty value for either is a 400.
The trailing slash is required.
Errors use the standardized envelope (v1 callers previously got {"detail": ...} or a bare list).
Bearer tokens are not accepted on v4: use JWT or a session. v1 accepts them until it is removed.
The v4 GET has no side effects. On sites with ENABLE_CREATOR_GROUP, v1 and v3 created an unrequested course-creator record (CourseCreator) as a side effect of this read, for a non-staff user who had none. Two other Studio reads still create it: the Studio home context (get_home_context, cms/djangoapps/contentstore/utils.py:1714, behind the v1 and v3 home endpoints) and the course rerun context (get_course_rerun_context, utils.py:1740).
POST /request_course_creator depends on that record (cms/djangoapps/contentstore/views/user.py:27-31). It calls user_requested_access, which does CourseCreator.objects.get(user=user) (cms/djangoapps/course_creators/views.py:89). On a site with ENABLE_CREATOR_GROUP, a non-staff author whose client has loaded neither the Studio home nor a course rerun context gets a 500 from that POST. No v4 endpoint creates the record (neither this list nor /api/authoring/v4/courses/), and this PR adds no POST to do it. A client that offers course-creator requests must still load the Studio home for the user first. The fix is tracked with the Studio home standardization, [API] Home Page Data #39068.
/api/authoring/v3/home/libraries/ was added by #39078, merged 2026-10-12 (cc @Abdul-Muqadim-Arbisoft). It is deprecated here because v4 is now this operation's current version.
Follow-ups
SDK: the view carries the openedx-platform-sdk tag, so the next openedx-platform-sdk regeneration gains v4_legacy_libraries_list. The v3 addresses are x-internal and drop out of generators that skip it.
frontend-app-authoring:
The libraries tab calls v1 and searches, filters and paginates the whole list client-side. Moving to v4 means paging (at most 100 per page) or asking for server-side search, before v1 and v3 are removed.
The draft FAA Make paver respect NO_PREREQ_INSTALL #3140 migrates to /api/contentstore/v3/home/libraries/, which is deprecated. It should target v4 instead (to be noted on FAA#3127).
Course-creator record, for [API] Home Page Data #39068: standardizing the Studio home endpoints under [API] Home Page Data #39068 would remove one of the two reads that still create the unrequestedCourseCreator record; the course rerun context is the other. Before that happens, POST /request_course_creator needs a write that creates the record: an explicit endpoint, or user_requested_access creating it when it is missing. This PR records the dependency and adds no POST.
edx-drf-extensions (library changes, not made here):
DefaultPagination.get_paginated_response_schema documents four of the seven keys, and the inherited page_size description gives neither the default nor the cap. The library fix should cover both. This PR adds the second local subclass, after CourseTextbookPagination. The two now differ, since only this one carries the page_size text. Keeping a second copy is an accepted risk for this PR; both subclasses go once the library fix is released. No issue or PR exists for it (searched 2026-10-14).
MethodNotAllowed and NotAcceptable are not cataloged, so a 405 or 406 is enveloped as internal / "Internal Server Error".
The exception handler returns the generic 500 envelope without logging the exception, so no traceback reaches the server log.
A keyed ValidationError is rendered into detail as the Python repr of the whole error dict.
Items 2 to 4 were not searched for existing issues.
CMS JSON 404: an address below /api/authoring/v4/legacy_libraries/ gets the CMS's HTML 404 page, even when the client asked for JSON. Fixing that for unmatched /api/ addresses belongs to the CMS handler404, or to a catch-all route under each collection.
Shared test helpers: the v4 tests import PASSWORD, SignalRecorder, generate_cms_schema, logged_in_client, resolve_ref and writes from cms/djangoapps/contentstore/rest_api/v2/views/tests/helpers.py, a module scoped to the v2 tests. Hoist them next to routed_actions in cms/djangoapps/contentstore/tests/utils.py, and leave a re-export in v2. Then a v2-only edit cannot change what the v4 tests prove, and retiring v2 cannot break them. Not done here, because it edits frozen v2 test code.
Later category-2 opt-ins (no version bump needed): an ordering parameter and a text-search parameter on v4.
Test environment: run in a Tutor container (openedx-dev:23.0.0-main) with openedx-core 1.11.0, openedx-authz 1.24.0 and openedx-forum 0.4.8 installed to match the pins (the image ships older releases). CI is the authoritative run.
Activity
Faraz32123 commentedon Oct 15, 2026
Standardization PR open: #39238
PR: #39238 — feat: apply FC-0118 ADRs to legacy libraries API
State: open
What this does
Standardizes the Libraries functional area (#39069, part of #38137). This area has one operation: "list the legacy (v1, modulestore) libraries the requester can read". Today it is served at three addresses across two versions; this PR adds its v4 at
/api/authoring/v4/legacy_libraries/.New addresses
/api/authoring/v4/legacy_libraries/(supersedesGET /api/contentstore/v1/home/libraries,GET /api/contentstore/v3/home/libraries/andGET /api/authoring/v3/home/libraries/, nowdeprecated: truein the CMS schema)ADRs applied
10 of 16 decisions applied on this pass; every one left open carries its reason.
path(..., as_view({"get": "list"})), not registered on a DRF Router, because a router names the routelegacy_library-listand ADR 0038 rule 11 asks for a snake_case name (legacy_library_list, like its siblingcourse_listin the same URLconf); merged feat: apply ADR 0038 (URL structure standardization) across 6 standardized APIs #39078, feat: apply FC-0118 ADRs to youtube transcripts APIs #39100 and feat: apply FC-0118 ADRs to course content APIs #39157 mount their ViewSets the same way. Otherwise met: plainViewSet(modulestore data path) with a service module; bounded query count; see the matrixDeprecated <link>marker is allowed now that [DEPR]: Contentstore and enrollment API versions superseded by FC-0118 #39128 is Plan Accepted, and is deliberately not added. See the matrixget_queryset()forScopedQuerysetMixinto wrap; the three layers are implemented in the service and tested (see the matrix)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
Schema: 0 breaking changes (69 → 70 paths). URLs: every base route keeps its pattern, name and view (2162 → 2163). The 24 legacy tests pass unmodified; v4 responses match v3 field for field (parity test, 20 rows).
Gates
Deprecations
GET /api/contentstore/v1/home/libraries,GET /api/contentstore/v3/home/libraries/andGET /api/authoring/v3/home/libraries/are superseded byGET /api/authoring/v4/legacy_libraries/. They are markeddeprecated: truein the published CMS schema; the v3 contentstore address was already marked through its/api/contentstore/v3/home/prefix. The superseded views are unchanged: no response header, and no deprecation notes in code./api/authoring/v3/home/and/api/authoring/v3/home/courses/remain current.Tracked on the FC-0118 umbrella DEPR ticket, #39128, which removes them one named release after the release this ships in. This area's entry: #39128 (comment)
Migration notes for callers:
{count, num_pages, current_page, start, next, previous, results}, 10 per page by default,page_sizeup to 100. Each item inresultshas the fields of an item in the oldlibrariesarray, under the same names.orgnow filters by the organization in the library key, as an exact, case-sensitive match; v1 and v3 documented it but ignored it.is_migratedbehaves as before. An empty value for either is a 400.{"detail": ...}or a bare list).ENABLE_CREATOR_GROUP, v1 and v3 created anunrequestedcourse-creator record (CourseCreator) as a side effect of this read, for a non-staff user who had none. Two other Studio reads still create it: the Studio home context (get_home_context,cms/djangoapps/contentstore/utils.py:1714, behind the v1 and v3homeendpoints) and the course rerun context (get_course_rerun_context,utils.py:1740).POST /request_course_creatordepends on that record (cms/djangoapps/contentstore/views/user.py:27-31). It callsuser_requested_access, which doesCourseCreator.objects.get(user=user)(cms/djangoapps/course_creators/views.py:89). On a site withENABLE_CREATOR_GROUP, a non-staff author whose client has loaded neither the Studio home nor a course rerun context gets a 500 from that POST. No v4 endpoint creates the record (neither this list nor/api/authoring/v4/courses/), and this PR adds no POST to do it. A client that offers course-creator requests must still load the Studio home for the user first. The fix is tracked with the Studio home standardization, [API] Home Page Data #39068./api/authoring/v3/home/libraries/was added by #39078, merged 2026-10-12 (cc @Abdul-Muqadim-Arbisoft). It is deprecated here because v4 is now this operation's current version.Follow-ups
SDK: the view carries the
openedx-platform-sdktag, so the next openedx-platform-sdk regeneration gainsv4_legacy_libraries_list. The v3 addresses arex-internaland drop out of generators that skip it.frontend-app-authoring:
/api/contentstore/v3/home/libraries/, which is deprecated. It should target v4 instead (to be noted on FAA#3127).Course-creator record, for [API] Home Page Data #39068: standardizing the Studio home endpoints under [API] Home Page Data #39068 would remove one of the two reads that still create the
unrequestedCourseCreatorrecord; the course rerun context is the other. Before that happens,POST /request_course_creatorneeds a write that creates the record: an explicit endpoint, oruser_requested_accesscreating it when it is missing. This PR records the dependency and adds no POST.edx-drf-extensions (library changes, not made here):
DefaultPagination.get_paginated_response_schemadocuments four of the seven keys, and the inheritedpage_sizedescription gives neither the default nor the cap. The library fix should cover both. This PR adds the second local subclass, afterCourseTextbookPagination. The two now differ, since only this one carries thepage_sizetext. Keeping a second copy is an accepted risk for this PR; both subclasses go once the library fix is released. No issue or PR exists for it (searched 2026-10-14).MethodNotAllowedandNotAcceptableare not cataloged, so a 405 or 406 is enveloped asinternal/ "Internal Server Error".ValidationErroris rendered intodetailas the Python repr of the whole error dict.Items 2 to 4 were not searched for existing issues.
CMS JSON 404: an address below
/api/authoring/v4/legacy_libraries/gets the CMS's HTML 404 page, even when the client asked for JSON. Fixing that for unmatched/api/addresses belongs to the CMShandler404, or to a catch-all route under each collection.Shared test helpers: the v4 tests import
PASSWORD,SignalRecorder,generate_cms_schema,logged_in_client,resolve_refandwritesfromcms/djangoapps/contentstore/rest_api/v2/views/tests/helpers.py, a module scoped to the v2 tests. Hoist them next torouted_actionsincms/djangoapps/contentstore/tests/utils.py, and leave a re-export in v2. Then a v2-only edit cannot change what the v4 tests prove, and retiring v2 cannot break them. Not done here, because it edits frozen v2 test code.Later category-2 opt-ins (no version bump needed): an
orderingparameter and a text-search parameter on v4.Test environment: run in a Tutor container (
openedx-dev:23.0.0-main) withopenedx-core1.11.0,openedx-authz1.24.0 andopenedx-forum0.4.8 installed to match the pins (the image ships older releases). CI is the authoritative run.🤖 Generated with Claude Code
Review on the PR, please — this issue stays open until it merges.