API endpoints should be properly organized around resources and follow RESTful principles. Avoid placing aggregation or utility endpoints in viewsets where they don't belong conceptually.
API endpoints should be properly organized around resources and follow RESTful principles. Avoid placing aggregation or utility endpoints in viewsets where they don’t belong conceptually.
Each viewset should represent a specific resource type, and endpoints within that viewset should operate on that resource. When you need aggregation endpoints or cross-resource operations, create dedicated API endpoints rather than forcing them into existing viewsets.
Example of what to avoid:
# DON'T: Adding aggregation endpoint to external_data_source viewset
class ExternalDataSourceViewSet(ModelViewSet):
@action(methods=["GET"], detail=False)
def dwh_scene_stats(self, request): # This doesn't belong here
# Returns aggregated data warehouse statistics
pass
Example of proper organization:
# DO: Create dedicated endpoint for aggregations
class DataWarehouseViewSet(ModelViewSet):
@action(methods=["GET"], detail=False)
def scene_stats(self, request):
# Returns aggregated data warehouse statistics
pass
For individual vs collection resources, handle both cases properly:
# Handle both individual survey and survey collection
def surveys(request: Request):
if survey_id:
# Return individual survey with proper error handling
try:
survey = Survey.objects.get(id=survey_id, team=team)
return JsonResponse({"survey": serialized_survey})
except Survey.DoesNotExist:
return JsonResponse({"error": "Survey not found"}, status=404)
# Return collection of surveys
return JsonResponse(get_surveys_response(team))
This approach makes APIs more intuitive, maintainable, and follows REST conventions that frontend developers expect.
Enter the URL of a public GitHub repository