Skip to content

refactor: migrate Xblock callers to standardized v1 REST endpoint (FC-0118)#3143

Draft
taimoor-ahmed-1 wants to merge 5 commits into
openedx:masterfrom
taimoor-ahmed-1:taimoor-ahmed/migrate-xblock-v1-rest
Draft

refactor: migrate Xblock callers to standardized v1 REST endpoint (FC-0118)#3143
taimoor-ahmed-1 wants to merge 5 commits into
openedx:masterfrom
taimoor-ahmed-1:taimoor-ahmed/migrate-xblock-v1-rest

Conversation

@taimoor-ahmed-1

Copy link
Copy Markdown

⛔ Draft — depends on a backend PR (do not merge yet)

Item #1 (Xblock) of the FC-0118 Studio-API caller migration tracked in
#3127.

Blocked by / merge after: openedx/openedx-platform#38908 — the v1 XblockViewSet
validates writes with a strict serializer that 400s on unlisted fields, and the
real Studio create payload sends library_content_key (v2-library import). That
backend PR declares the field on the serializer. This PR must not merge until
#38908 is merged and deployed
, or block creation/import will 400.

Independent of the Course Home (#3140) / Home Courses (#3139) drafts.

Description

Migrates Studio's xblock CRUD callers from the legacy /xblock/ Studio route to
the standardized /api/contentstore/v1/xblock/ REST endpoint (FC-0118,
ADR 0028/0037). The v1 XblockViewSet uses strict REST routing, so the verbs and
URLs change per operation:

Operation Legacy v1 REST
create / duplicate / paste POST /xblock/ POST /api/contentstore/v1/xblock/ (unchanged verb)
retrieve GET /xblock/{id} GET …/xblock/{id}/
update (metadata / publish / children / grader / access …) POST /xblock/{id} PATCH …/xblock/{id}/
move PATCH /xblock/ (collection) PATCH …/xblock/{sourceId}/ (detail)
delete DELETE /xblock/{id} DELETE …/xblock/{id}/
custom-pages "add page" PUT /xblock/ POST …/xblock/ (create)

Trailing slashes are required by the DRF DefaultRouter. For "move",
update_xblock_response still routes off move_source_locator in the body — the
URL key only scopes the permission check, so we PATCH the source block's detail URL.

Request-body changes (strict serializer)

The v1 serializer rejects unlisted top-level fields. Two fields the legacy route
ignored are dropped from request bodies:

  • type on create — redundant with category (category: category || type), which
    the backend actually reads.
  • courseKey on the editor save — not read by the update handler.

library_content_key (functional, library import) is kept and accepted by the
v1 serializer via #38908.

Left on the legacy route (NOT part of the v1 REST viewset)

These are handler/view sub-routes the v1 viewset does not serve, so they stay on
/xblock/…:

  • /xblock/outline/{id} (course-outline getXBlockApiUrl, content-tags-drawer)
  • /xblock/{id}/studio_view (editors blockStudioView)
  • /xblock/{id}/handler/… (editors transcripts, PdfEditor handler)

The editors block() URL helper is kept for those sub-routes; a new blockV1()
helper serves the CRUD callers (fetchBlockById, saveBlock, blockAncestor).

Files

Source

  • src/course-unit/data/api.ts — helpers → v1; editUnitDisplayName POST→PATCH; patchUnitItem (move) → PATCH source detail URL.
  • src/course-outline/data/api.ts — helpers → v1 (split out the legacy /xblock/outline/ builder); update calls POST→PATCH; drop type from create.
  • src/custom-pages/data/api.ts — delete/update → v1 detail; addCustomPage PUT→POST.
  • src/course-updates/data/api.js — handouts helper → v1 detail (GET + PUT).
  • src/editors/data/services/cms/{urls,api,utils}.ts — add blockV1() + patch() helper; fetchBlockById/saveBlockblockV1; saveBlock POST→PATCH; drop courseKey from normalizeContent.

Tests — mocks/verbs/assertions updated to match (course-unit, course-outline, custom-pages, editors).

Testing

  • npx jest src/course-unit → 210 pass
  • npx jest src/course-outline → 524 pass (1 pre-existing PageAlerts flake, unrelated: deprecated toBeCalled matcher, fails on master too)
  • npx jest src/custom-pages → pass (1 pre-existing date flake in UpdateForm, fails on master)
  • npx jest src/editors/data/services/cms → 75 pass; PdfEditor → 4 pass
  • dprint check + oxlint --deny-warnings on changed files → clean

Remaining failures in a full src/editors run are pre-existing (identical set on master: GalleryCard date, ImageUploadModal, SocialShareWidget, VideoEditorHandout) plus known parallel-run flakes.

Taimoor Ahmed and others added 5 commits July 20, 2026 00:47
…-0118)

FC-0118 (ADR 0028/0037): point Studio's xblock CRUD callers at the standardized
`/api/contentstore/v1/xblock/` REST endpoint instead of the legacy `/xblock/`
Studio route. The v1 XblockViewSet uses strict REST routing, so:

- create/duplicate/paste stay POST on the collection URL;
- retrieve stays GET, delete stays DELETE (now on the detail URL, trailing slash);
- legacy POST-as-update becomes PATCH (partial_update) on the detail URL;
- the "move" op (previously PATCH on the collection) becomes PATCH on the source
  block's detail URL — `update_xblock_response` still routes by `move_source_locator`;
- custom-pages "add page" (previously PUT on the collection) becomes POST (create).

Trailing slashes are required by the DRF DefaultRouter that serves the v1 viewset.

Fields the v1 strict serializer does not accept and the backend does not read are
dropped from request bodies: `type` (create; redundant with `category`) and
`courseKey` (editor save). `library_content_key` is kept (library import) and is
accepted by the v1 serializer via openedx/openedx-platform#38908.

The `/xblock/outline/...`, `/xblock/{id}/studio_view`, and `/xblock/{id}/handler/...`
sub-routes are NOT part of the v1 REST viewset and remain on the legacy route
(editors `block()` helper kept; new `blockV1()` helper added for CRUD).

Source-only commit; test mocks updated in follow-up commits.

Refs openedx#3127
Depends-on openedx/openedx-platform#38908

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…trailing slash)

Refs openedx#3127

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Detail-update mocks POST->PATCH; history assertions for updates read
history.patch; create expected bodies drop the dropped `type` key.

Refs openedx#3127

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Detail-update mocks POST->PATCH; move mocks PATCH the source detail URL;
create body-matchers/expected bodies drop the dropped `type` key; update
history assertions read history.patch.

Refs openedx#3127

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fetchBlockById/saveBlock use blockV1; saveBlock asserts PATCH; normalizeContent
tests drop learningContextId/courseKey; add blockV1 url test; PdfEditor save
mock targets the v1 detail PATCH URL.

Refs openedx#3127

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@openedx-webhooks

Copy link
Copy Markdown

Thanks for the pull request, @taimoor-ahmed-1!

This repository is currently maintained by @bradenmacdonald.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

🔘 Update the status of your PR

Your PR is currently marked as a draft. After completing the steps above, update its status by clicking "Ready for Review", or removing "WIP" from the title, as appropriate.


Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Jul 19, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Jul 19, 2026
@mphilbrick211 mphilbrick211 added the FC Relates to an Axim Funded Contribution project label Jul 20, 2026
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Waiting on Author in Contributions Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FC Relates to an Axim Funded Contribution project open-source-contribution PR author is not from Axim or 2U

Projects

Status: Waiting on Author

Development

Successfully merging this pull request may close these issues.

3 participants