From b1b47832f8a6c70f95c975eabecebeeddbfb1bfc Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Thu, 19 Mar 2026 17:44:18 +0500 Subject: [PATCH 1/5] docs: add ADR for standardizing restful api endpoints usage --- ...stful-api-endpoints-using-drf-viewsets.rst | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst diff --git a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst new file mode 100644 index 000000000000..405d464613e4 --- /dev/null +++ b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst @@ -0,0 +1,215 @@ +Standardize RESTful Endpoint Structure Using DRF ViewSets +========================================================= + +:Status: Proposed +:Date: 2026-03-19 +:Deciders: API Working Group +:Technical Story: Open edX REST API Standards - RESTful endpoint structure standardization using DRF ViewSets + +Context +------- + +Many Open edX platform API endpoints are currently implemented as separate, individual +class-based or function-based views for each HTTP action. Instead of using Django REST +Framework (DRF) ViewSets to group related operations into a single, cohesive class, each +action (list, retrieve, create, update, delete) is handled by its own standalone view. +This fragmented approach leads to significant code duplication, inconsistent behavior +across related endpoints, and an API layer that is difficult to extend or maintain. + +Additionally, some endpoints currently return both JSON and HTML responses depending on +the request context. Serving both response formats from a single endpoint violates the +principle of separation of concerns, creates confusion for external consumers and +automated systems, and increases the complexity of both the view logic and client-side +handling. + +Decision +-------- + +We will refactor all fragmented Open edX REST API endpoints to use DRF ViewSets, +consolidating related actions into unified, well-structured view classes. Additionally, +all API endpoints will be standardized to return only JSON responses, with all HTML +rendering logic relocated to dedicated Micro Frontend (MFE) pages. + +Implementation requirements: + +* All related API actions (list, retrieve, create, update, delete) **MUST** be + consolidated into a single DRF ViewSet per resource. +* Endpoints currently returning both JSON and HTML **MUST** be refactored to return only + JSON. HTML rendering must be moved to a dedicated MFE page. +* ViewSets **MUST** be registered using DRF Routers to ensure consistent, predictable + URL patterns. +* All ViewSets **MUST** use explicit serializers for both request validation and response + formatting (per ADR 0025). +* Multi-method handler functions (e.g., a single method handling DELETE, POST, and PUT) + **MUST** be refactored into properly documented, action-specific methods within a + ViewSet. +* Backward compatibility **MUST** be maintained during migration, using + versioned endpoints or deprecation notices. If a backwards incompatible change is + required, that change MUST be handled by creating a new version of the API and + transitioning to that API using the deprecation process. + + +Relevance in edx-platform +------------------------- + +Current patterns that should be migrated: + +* **Enrollment API** (``/api/enrollment/v1/``) - currently split across three + independent ``APIView`` classes, each handling a distinct part of the enrollment + resource: + + * ``EnrollmentListView(APIView, ApiKeyPermissionMixIn)`` - handles + ``GET /api/enrollment/v1/enrollment`` (list all enrollments for the current user) + and ``POST /api/enrollment/v1/enrollment`` (enroll a user in a course, with support + for mode, enrollment attributes, and enterprise consent). + * ``UnenrollmentView(APIView)`` - handles + ``POST /api/enrollment/v1/unenrollment``, a privileged service-only endpoint that + unenrolls a single user from all courses as part of the user retirement pipeline. + * ``EnrollmentAllowedView(APIView)`` - handles retrieval and creation of + ``CourseEnrollmentAllowed`` records for a given user email and course ID; restricted + to admin users via ``permissions.IsAdminUser``. + * These three views operate on the same enrollment resource and should be unified into + a single ``EnrollmentViewSet``. + +* **Assets Handling Endpoints** - currently exhibit two distinct issues: + + * A single handler function mixes DELETE, POST, and PUT operations without clear + separation of concerns. + * The endpoint checks the ``HTTP_ACCEPT`` header and returns either JSON or HTML + depending on the request, mixing response formats in a single view. + * **Resolution:** Refactor into a properly documented ``AssetsViewSet`` with distinct + action methods. Create a dedicated MFE page for all HTML rendering; the endpoint + returns only JSON. + +Illustrative Example +-------------------- + +The following shows the structural pattern being replaced and the target pattern. +Full implementation details will be addressed during the migration of each endpoint. + +**Before - Enrollment API (current fragmented pattern):** + +.. code-block:: python + + # Three separate APIView classes for one logical resource + class EnrollmentListView(APIView, ApiKeyPermissionMixIn): ... + class UnenrollmentView(APIView): ... # privileged, retirement pipeline only + class EnrollmentAllowedView(APIView): ... # admin-only, CourseEnrollmentAllowed records + +**After - Consolidated into a single ViewSet:** + +.. code-block:: python + + class EnrollmentViewSet(viewsets.ViewSet): + # viewsets.ViewSet used intentionally — enrollment logic routes through + # the api module, not direct ORM, so ModelViewSet is not appropriate. + + def list(self, request): ... + def create(self, request): ... + + @action(detail=False, methods=["post"], url_path="unenrollment", + permission_classes=[ApiKeyHeaderPermission]) + def unenroll(self, request): ... # preserves privileged-only restriction + + @action(detail=False, methods=["get", "post"], url_path="allowed", + permission_classes=[permissions.IsAdminUser], + throttle_classes=[EnrollmentUserThrottle]) + def allowed(self, request): ... # reuses existing CourseEnrollmentAllowedSerializer + + router = DefaultRouter() + router.register(r"enrollment", EnrollmentViewSet, basename="enrollment") + +**Before - Assets handler (current mixed-format pattern):** + +.. code-block:: python + + # Single function-based view — returns HTML or JSON depending on HTTP_ACCEPT, + # with GET, POST, PUT, and DELETE all dispatched inside handle_assets(). + @login_required + @ensure_csrf_cookie + def assets_handler(request, course_key_string=None, asset_key_string=None): + return handle_assets(request, course_key_string, asset_key_string) + +**After - Dedicated ViewSet, JSON only:** + +.. code-block:: python + + class AssetsViewSet(viewsets.ViewSet): + # HTML rendering moved to Studio MFE. + # Reuses existing asset_storage_handlers service functions. + def list(self, request, course_key_string): ... # GET - paginated asset list + def create(self, request, course_key_string): ... # POST - upload asset + def update(self, request, course_key_string, pk): ... # PUT - update lock state + def destroy(self, request, course_key_string, pk): ...# DELETE - remove asset + +Consequences +------------ + +Positive +~~~~~~~~ + +* Consistent, discoverable API structure that is easier for developers and third-party + integrators to understand and consume. +* Significant reduction in code duplication by consolidating related operations into a + single ViewSet class. +* Improved maintainability - changes to a resource's API logic are localized to one + ViewSet rather than scattered across multiple view files. +* DRF Routers automatically generate standard URL patterns, reducing manual URL + configuration and human error. +* Clear separation of concerns: API endpoints serve data (JSON only); MFEs handle all + HTML rendering. +* Improved compatibility with AI systems, automated testing frameworks, and third-party + integrations that expect predictable, JSON-only responses. +* Enables automatic API schema generation and documentation (e.g., via + ``drf-spectacular`` or ``drf-yasg``). + +Negative / Trade-offs +~~~~~~~~~~~~~~~~~~~~~ + +* Refactoring existing fragmented views into ViewSets requires non-trivial upfront + development effort. +* Existing URL patterns may change during migration, requiring updates to client-side + code, documentation, and any hardcoded references. +* HTML-rendering logic must be migrated to MFE pages, which requires coordination with + frontend teams and may extend the migration timeline. +* Teams unfamiliar with DRF ViewSets and Routers will require onboarding before + contributing to migrated endpoints. + +Alternatives Considered +----------------------- + +* **Keep fragmented APIView classes:** Rejected. Maintains code duplication, + inconsistency, and high maintenance burden across related operations. +* **Use DRF GenericAPIView with mixins:** Partially considered but rejected as the + primary approach. While mixins reduce some duplication, they do not provide the same + level of structural consolidation or automatic router integration as ViewSets. +* **Continue serving both JSON and HTML from the same endpoint:** Rejected. Mixing + response formats in a single endpoint violates separation of concerns, increases + complexity, and creates an unreliable contract for API consumers. + +Rollout Plan +------------ + +1. Audit existing API endpoints to identify all fragmented view patterns and endpoints + with mixed JSON/HTML responses. +2. Prioritize high-impact resources for migration: Enrollment API, Assets endpoints, and + any other endpoints identified in the audit. +3. Coordinate with frontend teams to create corresponding MFE pages for any endpoints + currently serving HTML. +4. Refactor identified endpoints into DRF ViewSets, registered via DRF Routers. Ensure + all ViewSets use explicit serializers per ADR 0025. +5. Update and expand test coverage to validate correct behavior of all refactored + ViewSet actions and confirm JSON-only responses. +6. Publish deprecation notices for any legacy URL patterns that will be replaced, + providing clear migration guidance to internal and external API consumers. +7. Update API documentation to reflect the new ViewSet-based structure, URL patterns, + and JSON-only response contracts. + +References +---------- + +* Django REST Framework documentation - ViewSets: + https://www.django-rest-framework.org/api-guide/viewsets/ +* Django REST Framework documentation - Routers: + https://www.django-rest-framework.org/api-guide/routers/ + \ No newline at end of file From c2ba44019a3458133c74be059d7dcd750883ece6 Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Wed, 25 Mar 2026 12:27:51 +0500 Subject: [PATCH 2/5] docs: mention only drf-spectacular for API schema generation and documentation --- ...8-standardize-restful-api-endpoints-using-drf-viewsets.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst index 405d464613e4..a63fc12c05e2 100644 --- a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst +++ b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst @@ -48,7 +48,6 @@ Implementation requirements: required, that change MUST be handled by creating a new version of the API and transitioning to that API using the deprecation process. - Relevance in edx-platform ------------------------- @@ -160,8 +159,7 @@ Positive HTML rendering. * Improved compatibility with AI systems, automated testing frameworks, and third-party integrations that expect predictable, JSON-only responses. -* Enables automatic API schema generation and documentation (e.g., via - ``drf-spectacular`` or ``drf-yasg``). +* Enables automatic API schema generation and documentation via ``drf-spectacular``. Negative / Trade-offs ~~~~~~~~~~~~~~~~~~~~~ From 5cccb5447402b2779c9f4646310949cb9a29ea5f Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Wed, 1 Apr 2026 18:20:38 +0500 Subject: [PATCH 3/5] docs: add decision for moving legacy views to DRF In this commit, Instead of creating a new ADR, add decision for moving legacy Django views to DRF to similar existing ADR. Its related issue is: https://github.com/openedx/openedx-platform/issues/38168 --- ...stful-api-endpoints-using-drf-viewsets.rst | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst index a63fc12c05e2..ec2b0ada7c20 100644 --- a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst +++ b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst @@ -1,16 +1,16 @@ -Standardize RESTful Endpoint Structure Using DRF ViewSets -========================================================= +Standardize RESTful Endpoint Structure Using DRF ViewSets and also port legacy views to DRF endpoints +===================================================================================================== :Status: Proposed :Date: 2026-03-19 :Deciders: API Working Group -:Technical Story: Open edX REST API Standards - RESTful endpoint structure standardization using DRF ViewSets +:Technical Story: Open edX REST API Standards - RESTful endpoint structure standardization using DRF ViewSets and also port legacy views to DRF endpoints Context ------- Many Open edX platform API endpoints are currently implemented as separate, individual -class-based or function-based views for each HTTP action. Instead of using Django REST +class-based or function-based (legacy) views for each HTTP action. Instead of using Django REST Framework (DRF) ViewSets to group related operations into a single, cohesive class, each action (list, retrieve, create, update, delete) is handled by its own standalone view. This fragmented approach leads to significant code duplication, inconsistent behavior @@ -43,6 +43,8 @@ Implementation requirements: * Multi-method handler functions (e.g., a single method handling DELETE, POST, and PUT) **MUST** be refactored into properly documented, action-specific methods within a ViewSet. +* Legacy views should be migrated to ViewSets. And **APIView** should be used for + non-resource endpoints where ViewSets are not a good fit. * Backward compatibility **MUST** be maintained during migration, using versioned endpoints or deprecation notices. If a backwards incompatible change is required, that change MUST be handled by creating a new version of the API and @@ -80,6 +82,12 @@ Current patterns that should be migrated: action methods. Create a dedicated MFE page for all HTML rendering; the endpoint returns only JSON. +* **Legacy Django Views** - Many endpoints still use plain Django views instead of DRF: + * Hard-coded JSON responses using ``HttpResponse(json.dumps(...))`` instead of serializers + * Manual method dispatch instead of DRF mixins and ViewSets + * Missing DRF features like automatic authentication, permission classes, and schema generation + * Inconsistent error handling and response formats + Illustrative Example -------------------- @@ -141,6 +149,39 @@ Full implementation details will be addressed during the migration of each endpo def update(self, request, course_key_string, pk): ... # PUT - update lock state def destroy(self, request, course_key_string, pk): ...# DELETE - remove asset +**Before - Legacy Django View:** + +.. code-block:: python + + from django.http import JsonResponse, HttpResponse + from django.views.decorators.http import require_GET + + @require_GET + @login_required + def notes(request, course_id): + # Manual parsing, no serializer, ad-hoc error shape + data = get_notes_data(request.user, course_id) + return HttpResponse(json.dumps(data, cls=NoteJSONEncoder), + content_type="application/json") + +**After - DRF ViewSet with serializer:** + +.. code-block:: python + + from rest_framework import viewsets, serializers + from rest_framework.decorators import action + + class NotesViewSet(viewsets.ReadOnlyModelViewSet): + serializer_class = NotesSerializer + permission_classes = [IsAuthenticated] + + def get_queryset(self): + return get_notes_queryset(self.request, self.kwargs["course_id"]) + + def list(self, request, *args, **kwargs): + serializer = self.get_serializer(self.get_queryset(), many=True) + return Response(serializer.data) + Consequences ------------ @@ -188,8 +229,8 @@ Alternatives Considered Rollout Plan ------------ -1. Audit existing API endpoints to identify all fragmented view patterns and endpoints - with mixed JSON/HTML responses. +1. Audit existing API endpoints to identify all fragmented view patterns, legacy Django + views, and endpoints with mixed JSON/HTML responses. 2. Prioritize high-impact resources for migration: Enrollment API, Assets endpoints, and any other endpoints identified in the audit. 3. Coordinate with frontend teams to create corresponding MFE pages for any endpoints @@ -210,4 +251,3 @@ References https://www.django-rest-framework.org/api-guide/viewsets/ * Django REST Framework documentation - Routers: https://www.django-rest-framework.org/api-guide/routers/ - \ No newline at end of file From b076b7282a477fde8cc6e1e52b92c43bb438d83e Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Mon, 6 Apr 2026 23:50:51 +0500 Subject: [PATCH 4/5] docs: remove DRF content negotiation restrictions --- ...stful-api-endpoints-using-drf-viewsets.rst | 56 ++++++------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst index ec2b0ada7c20..8f1fb8d078d4 100644 --- a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst +++ b/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst @@ -16,26 +16,16 @@ action (list, retrieve, create, update, delete) is handled by its own standalone This fragmented approach leads to significant code duplication, inconsistent behavior across related endpoints, and an API layer that is difficult to extend or maintain. -Additionally, some endpoints currently return both JSON and HTML responses depending on -the request context. Serving both response formats from a single endpoint violates the -principle of separation of concerns, creates confusion for external consumers and -automated systems, and increases the complexity of both the view logic and client-side -handling. - Decision -------- We will refactor all fragmented Open edX REST API endpoints to use DRF ViewSets, -consolidating related actions into unified, well-structured view classes. Additionally, -all API endpoints will be standardized to return only JSON responses, with all HTML -rendering logic relocated to dedicated Micro Frontend (MFE) pages. +consolidating related actions into unified, well-structured view classes. Implementation requirements: * All related API actions (list, retrieve, create, update, delete) **MUST** be consolidated into a single DRF ViewSet per resource. -* Endpoints currently returning both JSON and HTML **MUST** be refactored to return only - JSON. HTML rendering must be moved to a dedicated MFE page. * ViewSets **MUST** be registered using DRF Routers to ensure consistent, predictable URL patterns. * All ViewSets **MUST** use explicit serializers for both request validation and response @@ -72,15 +62,12 @@ Current patterns that should be migrated: * These three views operate on the same enrollment resource and should be unified into a single ``EnrollmentViewSet``. -* **Assets Handling Endpoints** - currently exhibit two distinct issues: +* **Assets Handling Endpoints** - currently exhibit a distinct issue: * A single handler function mixes DELETE, POST, and PUT operations without clear separation of concerns. - * The endpoint checks the ``HTTP_ACCEPT`` header and returns either JSON or HTML - depending on the request, mixing response formats in a single view. * **Resolution:** Refactor into a properly documented ``AssetsViewSet`` with distinct - action methods. Create a dedicated MFE page for all HTML rendering; the endpoint - returns only JSON. + action methods. * **Legacy Django Views** - Many endpoints still use plain Django views instead of DRF: * Hard-coded JSON responses using ``HttpResponse(json.dumps(...))`` instead of serializers @@ -126,23 +113,22 @@ Full implementation details will be addressed during the migration of each endpo router = DefaultRouter() router.register(r"enrollment", EnrollmentViewSet, basename="enrollment") -**Before - Assets handler (current mixed-format pattern):** +**Before - Assets handler (current pattern):** .. code-block:: python - # Single function-based view — returns HTML or JSON depending on HTTP_ACCEPT, - # with GET, POST, PUT, and DELETE all dispatched inside handle_assets(). + # Single function-based view with GET, POST, PUT, and DELETE all dispatched + # inside handle_assets(). @login_required @ensure_csrf_cookie def assets_handler(request, course_key_string=None, asset_key_string=None): return handle_assets(request, course_key_string, asset_key_string) -**After - Dedicated ViewSet, JSON only:** +**After - Dedicated ViewSet:** .. code-block:: python class AssetsViewSet(viewsets.ViewSet): - # HTML rendering moved to Studio MFE. # Reuses existing asset_storage_handlers service functions. def list(self, request, course_key_string): ... # GET - paginated asset list def create(self, request, course_key_string): ... # POST - upload asset @@ -196,10 +182,8 @@ Positive ViewSet rather than scattered across multiple view files. * DRF Routers automatically generate standard URL patterns, reducing manual URL configuration and human error. -* Clear separation of concerns: API endpoints serve data (JSON only); MFEs handle all - HTML rendering. * Improved compatibility with AI systems, automated testing frameworks, and third-party - integrations that expect predictable, JSON-only responses. + integrations that expect predictable, standardized responses. * Enables automatic API schema generation and documentation via ``drf-spectacular``. Negative / Trade-offs @@ -209,8 +193,6 @@ Negative / Trade-offs development effort. * Existing URL patterns may change during migration, requiring updates to client-side code, documentation, and any hardcoded references. -* HTML-rendering logic must be migrated to MFE pages, which requires coordination with - frontend teams and may extend the migration timeline. * Teams unfamiliar with DRF ViewSets and Routers will require onboarding before contributing to migrated endpoints. @@ -221,28 +203,22 @@ Alternatives Considered inconsistency, and high maintenance burden across related operations. * **Use DRF GenericAPIView with mixins:** Partially considered but rejected as the primary approach. While mixins reduce some duplication, they do not provide the same - level of structural consolidation or automatic router integration as ViewSets. -* **Continue serving both JSON and HTML from the same endpoint:** Rejected. Mixing - response formats in a single endpoint violates separation of concerns, increases - complexity, and creates an unreliable contract for API consumers. + level of structural consolidation or URL standardization as ViewSets with routers. Rollout Plan ------------ -1. Audit existing API endpoints to identify all fragmented view patterns, legacy Django - views, and endpoints with mixed JSON/HTML responses. +1. Audit existing API endpoints to identify all fragmented view patterns and legacy Django + views. 2. Prioritize high-impact resources for migration: Enrollment API, Assets endpoints, and any other endpoints identified in the audit. -3. Coordinate with frontend teams to create corresponding MFE pages for any endpoints - currently serving HTML. -4. Refactor identified endpoints into DRF ViewSets, registered via DRF Routers. Ensure +3. Refactor identified endpoints into DRF ViewSets, registered via DRF Routers. Ensure all ViewSets use explicit serializers per ADR 0025. -5. Update and expand test coverage to validate correct behavior of all refactored - ViewSet actions and confirm JSON-only responses. -6. Publish deprecation notices for any legacy URL patterns that will be replaced, +4. Update and expand test coverage to validate correct behavior of all refactored + ViewSet actions. +5. Publish deprecation notices for any legacy URL patterns that will be replaced, providing clear migration guidance to internal and external API consumers. -7. Update API documentation to reflect the new ViewSet-based structure, URL patterns, - and JSON-only response contracts. +6. Update API documentation to reflect the new ViewSet-based structure and URL patterns. References ---------- From 18a1817dc221f6fa31db05e7e3ee8ae2430120f6 Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Fri, 17 Apr 2026 11:30:25 +0500 Subject: [PATCH 5/5] docs: address suggestions --- ...endpoints-using-standard-drf-viewsets.rst} | 49 ++++--------------- 1 file changed, 10 insertions(+), 39 deletions(-) rename docs/decisions/{0028-standardize-restful-api-endpoints-using-drf-viewsets.rst => 0028-migrate-restful-and-legacy-api-endpoints-using-standard-drf-viewsets.rst} (84%) diff --git a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst b/docs/decisions/0028-migrate-restful-and-legacy-api-endpoints-using-standard-drf-viewsets.rst similarity index 84% rename from docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst rename to docs/decisions/0028-migrate-restful-and-legacy-api-endpoints-using-standard-drf-viewsets.rst index 8f1fb8d078d4..102a2c374b40 100644 --- a/docs/decisions/0028-standardize-restful-api-endpoints-using-drf-viewsets.rst +++ b/docs/decisions/0028-migrate-restful-and-legacy-api-endpoints-using-standard-drf-viewsets.rst @@ -1,10 +1,10 @@ -Standardize RESTful Endpoint Structure Using DRF ViewSets and also port legacy views to DRF endpoints -===================================================================================================== +Migrating RESTful & Legacy Django API Endpoints to Standard DRF ViewSets +======================================================================== :Status: Proposed :Date: 2026-03-19 :Deciders: API Working Group -:Technical Story: Open edX REST API Standards - RESTful endpoint structure standardization using DRF ViewSets and also port legacy views to DRF endpoints +:Technical Story: Open edX REST API Standards - RESTful & Legacy Django API endpoint structure standardization using DRF ViewSets Context ------- @@ -30,6 +30,9 @@ Implementation requirements: URL patterns. * All ViewSets **MUST** use explicit serializers for both request validation and response formatting (per ADR 0025). +* All ViewSets **MUST** optimize their ``get_queryset`` method using ``select_related`` + and ``prefetch_related`` to match the fields required by their serializers, preventing + N+1 query regressions. * Multi-method handler functions (e.g., a single method handling DELETE, POST, and PUT) **MUST** be refactored into properly documented, action-specific methods within a ViewSet. @@ -135,39 +138,6 @@ Full implementation details will be addressed during the migration of each endpo def update(self, request, course_key_string, pk): ... # PUT - update lock state def destroy(self, request, course_key_string, pk): ...# DELETE - remove asset -**Before - Legacy Django View:** - -.. code-block:: python - - from django.http import JsonResponse, HttpResponse - from django.views.decorators.http import require_GET - - @require_GET - @login_required - def notes(request, course_id): - # Manual parsing, no serializer, ad-hoc error shape - data = get_notes_data(request.user, course_id) - return HttpResponse(json.dumps(data, cls=NoteJSONEncoder), - content_type="application/json") - -**After - DRF ViewSet with serializer:** - -.. code-block:: python - - from rest_framework import viewsets, serializers - from rest_framework.decorators import action - - class NotesViewSet(viewsets.ReadOnlyModelViewSet): - serializer_class = NotesSerializer - permission_classes = [IsAuthenticated] - - def get_queryset(self): - return get_notes_queryset(self.request, self.kwargs["course_id"]) - - def list(self, request, *args, **kwargs): - serializer = self.get_serializer(self.get_queryset(), many=True) - return Response(serializer.data) - Consequences ------------ @@ -214,11 +184,12 @@ Rollout Plan any other endpoints identified in the audit. 3. Refactor identified endpoints into DRF ViewSets, registered via DRF Routers. Ensure all ViewSets use explicit serializers per ADR 0025. -4. Update and expand test coverage to validate correct behavior of all refactored +4. Include a comparison of SQL query counts to ensure no performance degradation. +5. Update and expand test coverage to validate correct behavior of all refactored ViewSet actions. -5. Publish deprecation notices for any legacy URL patterns that will be replaced, +6. Publish deprecation notices for any legacy URL patterns that will be replaced, providing clear migration guidance to internal and external API consumers. -6. Update API documentation to reflect the new ViewSet-based structure and URL patterns. +7. Update API documentation to reflect the new ViewSet-based structure and URL patterns. References ----------