I asked Claude to generate a summary of these PRs, and here’s the result:
Below is a high-level summary of the seven ADRs currently up for review, along with key decisions and points worth discussing. I hope this is useful as a companion to the individual PRs.
Overview
All seven ADRs represent a coordinated effort to eliminate inconsistency across the Open edX platform’s REST API layer as part of FC-0118. The common thread: many endpoints were built ad hoc over the years, and they now diverge in how they handle serialization, authorization, documentation, URL structure, error formatting, and HTTP semantics. These ADRs propose a set of standards to bring them into alignment.
Two ADRs have already merged (0025 and 0026). Five are open for review.
ADR-by-ADR Summary
ADR 0025 — Standardize Serializer Usage (PR #38139, PR #38188)
Merged
Problem: Many endpoints manually construct JSON responses using Python dicts instead of DRF serializers, leading to inconsistent schemas and making automated tooling (including AI integrations) unreliable.
Decision: All API views must use explicit DRF serializers for both request validation and response formatting. Manual JSON construction is to be replaced.
Key points:
- Serializers must include field descriptions and validation rules.
- A follow-up amendment (PR #38188) clarified that if full backward compatibility isn’t achievable, a new API version must be created and the old one deprecated — not silently broken.
- Alternatives like Pydantic and dataclasses were considered and rejected to avoid introducing a third pattern alongside existing DRF serializers and manual dicts.
Possible discussion points:
- How do we handle
ModelSerializer-heavy endpoints where field exposure is difficult to predict?
- What’s the migration priority order — are there particularly high-traffic or externally-consumed endpoints that should go first?
ADR 0026 — Standardize Permission Classes (PR #38187)
Merged
Problem: Authorization logic is scattered across custom decorators, inline role checks, and embedded logic within views — creating security gaps and making access patterns difficult to audit.
Decision: All API views must declare authorization via permission_classes on the DRF view. Inline role checks and custom decorators should be replaced with reusable BasePermission subclasses.
Key points:
- This ADR standardizes the DRF integration surface for authorization, not the underlying policy engine. Existing legacy checks or future engines (e.g. Casbin) can be wrapped inside permission classes during phased migrations.
- Object-level permissions (
has_object_permission) are explicitly encouraged.
Possible discussion points:
- What’s the recommended pattern for views that currently mix
IsAuthenticated with legacy Django permission checks? Should there be shared base classes provided by the working group?
- How should permission classes interact with API key authentication (e.g.
ApiKeyPermissionMixIn)?
ADR 0027 — Standardize API Documentation & Schema Coverage (PR #38189)
Open for Review
Problem: Many views lack OpenAPI schema decorators, making endpoints undiscoverable for external developers, AI agents, and integration tooling. Duplicate endpoints have also emerged partly due to poor discoverability.
Decision: All endpoints must use drf-spectacular with @extend_schema decorators, covering request/response schemas, status codes, and error conditions.
Key points:
- Documentation must include descriptions and examples for complex endpoints.
- The ADR explicitly calls out AI-tool discoverability as a motivation alongside standard developer experience goals.
Possible discussion points:
- Should there be a linting or CI gate that fails builds when views lack
@extend_schema?
drf-spectacular is already used in parts of the platform — are there any incompatibilities or known gaps with existing auto-generated schemas?
ADR 0028 — Standardize RESTful Endpoints Using DRF ViewSets (PR #38191)
Open for Review
Problem: Related API actions (list, retrieve, create, update, delete) are often spread across separate APIView classes with duplicated logic, making the codebase hard to maintain and extend.
Decision: Related actions must be consolidated into DRF ViewSets registered via DRF Routers.
Key points:
get_queryset must use select_related/prefetch_related to prevent N+1 query regressions during migrations.
- Multi-method handler functions (e.g. a single method dispatching DELETE, POST, and PUT) must be broken into action-specific ViewSet methods.
- Backward compatibility must be maintained; breaking changes require API versioning + deprecation.
- The Enrollment API (three separate
APIView classes for one resource) and the Assets handling endpoint are called out as specific migration targets.
Possible discussion points:
- ViewSets impose a fairly specific URL shape via DRF Routers — are there cases in the platform where existing URL patterns can’t easily conform to this without breaking external clients?
- How should custom actions (
@action decorator) be documented in the standard? Some of the existing fragmented endpoints are conceptually “actions on a resource” rather than standard CRUD.
- This ADR and ADR 0031 (“Merge Similar Endpoints”) are closely related — should they be read as a sequence, or could they conflict on some endpoints?
ADR 0029 — Standardize Error Responses (PR #38246)
Open for Review
Problem: Open edX APIs return errors in multiple incompatible shapes — {"error": ...}, {"detail": ...}, nested field dicts, and even HTTP 200 with "success": false. This makes reliable error handling impossible for clients.
Decision: All non-2xx responses must use a structured JSON error object loosely based on RFC 9457 (Problem Details).
Key points:
- Core fields:
type (URI identifier), title, status, detail, instance (request path).
- Optional
user_message field for MFE/end-user display; MFEs should prefer mapping type URIs to locally-translated strings.
- Validation errors use a predictable
errors dict (field → list of messages), mapping directly onto DRF’s native ValidationError.detail.
- A catalog of common
type URIs is proposed: https://openedx.org/errors/not-found, authz, authn, validation, rate-limited, internal. App-specific types may extend this but must use absolute URIs.
- The ADR explicitly prohibits masking errors behind HTTP 200.
Possible discussion points:
- The
openedx.org/errors/* URIs need to actually resolve to documentation eventually — who owns that and what’s the timeline?
- How should the central DRF exception handler be shipped and adopted across repos? Will it live in
edx-drf-extensions or openedx-platform?
- The
user_message field is optional. Should there be guidance on when it’s appropriate vs. relying on type-based client-side translation?
ADR 0030 — Ensure GET Requests Are Idempotent (PR #38249)
Open for Review
Problem: Some GET endpoints fire openedx-events, Django signals, or trigger writes as side-effects. This violates REST safety semantics, breaks caching proxies, and creates invisible domain-state mutations.
Decision: GET handlers must be strictly read-only with respect to domain state. Side-effecting operations must be moved to explicit write endpoints (POST/PUT/PATCH).
Key points:
- Firing
openedx-events or Django signals from GET handlers is explicitly prohibited — this is called the “primary concern” because signal receivers can cause downstream domain writes invisible to the GET handler.
- Pure telemetry writes to a separate analytics store (e.g.
tracker.emit, Segment) are acceptable inside GET if they don’t affect domain state and don’t involve openedx-events/signals.
- Regression tests must be added to ensure
GET handlers remain side-effect free.
- Specific call-outs: discussion views, legacy courseware code, and
student app code that emit analytics in GET paths.
Possible discussion points:
- The telemetry carve-out (pure analytics writes are OK) may be unclear in practice — when does an analytics write risk affecting domain state? Could this exception be tightened?
- How should teams handle endpoints where the
GET side-effect is intentional and relied upon by downstream systems? Is the migration path just “add a POST endpoint and deprecate the side-effect”?
- Are there automated detection strategies (AST analysis, test tooling) being considered to find non-idempotent GETs across the codebase?
ADR 0031 — Merge Similar Endpoints (PR #38262)
Open for Review
Problem: The platform has grown clusters of near-identical endpoints for the same resource domain (e.g. three separate certificate endpoints: enable_certificate_generation, start_certificate_generation, start_certificate_regeneration), each independently duplicating permission checks, serialization logic, and audit logging.
Decision: Groups of closely related endpoints should be consolidated into a single parameterized DRF view, using an action or mode request parameter to distinguish operations.
Key points:
- Shared logic (permissions, validation, audit logging) should move into a common service layer or mixin.
- URL aliases or deprecation redirects must preserve backward compatibility during the transition window.
- The unified endpoint schema must be fully documented via drf-spectacular, including the enumerated set of valid
action/mode values.
Possible discussion points:
- Using an
action parameter to dispatch to different operations is a departure from pure REST conventions — is there a preference for using HTTP verbs semantically vs. a parameter-based dispatch approach?
- How does this ADR interact with ADR 0028 (ViewSets)? The ViewSet pattern via DRF Routers already groups related actions — is the
action/mode parameter pattern intended for cases where standard CRUD verbs don’t map cleanly?
- Certificate generation as a motivating example involves Celery background tasks. Should the ADR address async patterns (e.g. returning a task ID + polling endpoint) as part of consolidation?
Cross-Cutting Themes
A few themes run across multiple ADRs that might be worth discussing holistically:
Backward compatibility and versioning — ADRs 0025, 0026, 0028, and 0031 all touch this. The consistent answer is: “maintain compatibility; if you can’t, version the API.” It would be worth agreeing on a canonical deprecation timeline and whether there’s tooling (e.g. a deprecation header or registry) to help track it.
AI/machine discoverability — ADRs 0025, 0027, and 0029 all explicitly mention AI tools as a beneficiary of these changes. This is a significant framing shift for API design guidance and worth acknowledging as a stated goal.
Migration sequencing — These seven ADRs are interdependent (e.g. ViewSets depend on Serializers; Documentation depends on Serializers and ViewSets; Error responses work best with proper HTTP status codes from all layers). Is there a recommended adoption order, or will teams apply them incrementally?
Enforcement — None of the ADRs currently specify CI enforcement. Community input on which of these could or should be lint/tested in CI would strengthen the overall proposal.
Summary prepared based on the ADR content in PRs #38139, #38188, #38187, #38189, #38191, #38246, #38249, and #38262. Please refer to the original PRs for full detail and normative text.