Endpoints for Models0%
Endpoints for Models
Beginner12 min read•Updated: Jul 11, 2026
Designing Clean RESTful Model Endpoints
Designing an intuitive, predictable REST API is an art. Clean API endpoints conform to standard industry conventions, use intuitive hierarchical relationships, handle query parameters cleanly, and provide consistent metadata wrappers.
1. RESTful URL Design Standards
Output
Standard REST Hierarchy:
/api/v1/{collection}/ ──► Collection Endpoint (GET list, POST create)
/api/v1/{collection}/{id}/ ──► Detail Endpoint (GET, PUT, PATCH, DELETE)
/api/v1/{collection}/{id}/{sub-collection}/ ──► Nested Resource Endpoint
Golden Rules:
- 1Always use lowercase plural nouns:
/api/v1/customers/(not/Customeror/getCustomer). - 2Represent hierarchies naturally:
/api/v1/projects/{id}/tasks/indicates tasks belonging to a specific project. - 3Limit nesting depth: Avoid nesting deeper than 2 levels (
/orgs/1/projects/2/tasks/3/comments/4is an anti-pattern!). Flatten deep children:/api/v1/tasks/{task_id}/comments/. - 4Use query parameters for filtering and pagination:
/api/v1/articles/?status=published&category=tech&page=2.
2. Implementing Nested Child Endpoints in DRF
Python
# tasks/views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from .models import Task
from .serializers import TaskSerializer
class ProjectTasksViewSet(ModelViewSet):
serializer_class = TaskSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
# Scope tasks strictly to project ID extracted from URL kwargs
project_id = self.kwargs["project_pk"]
return Task.objects.filter(project_id=project_id, project__owner=self.request.user)
def perform_create(self, serializer):
project_id = self.kwargs["project_pk"]
serializer.save(project_id=project_id)
3. Response Structure & Metadata Envelopes
While standard DRF endpoints return bare JSON arrays or objects, enterprise platforms frequently wrap responses in standard metadata envelopes:
JSON
{
"data": {
"id": "proj_9912",
"name": "Cloud Security Architecture",
"status": "active"
},
"meta": {
"timestamp": "2026-09-15T04:45:00Z",
"version": "v1.2"
}
}
4. Sub-resource Actions via @action
When a model needs a non-CRUD business operation (e.g. archiving a project or sending an invoice):
Python
from rest_framework.decorators import action
from rest_framework.response import Response
class ProjectViewSet(ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
# POST /api/v1/projects/{pk}/archive/
@action(detail=True, methods=["post"], url_path="archive")
def archive_project(self, request, pk=None):
project = self.get_object()
project.status = "archived"
project.save()
return Response({"status": "Project archived successfully"})
Interactive Quiz
Practice Quiz
Question 1
Which of the following is considered a best-practice RESTful URI design?
Question 2
Why is deep URL nesting (e.g. /companies/1/departments/2/teams/3/members/4/tasks/5/) discouraged?
Question 3
How do you define a custom RPC-style action on a single model instance in a DRF ViewSet?
Question 4
What does the detail=False argument on an @action decorator indicate?
Question 5
Why should API versioning (e.g. /api/v1/) be included in endpoint URI designs from day one?
Next Lesson
URL Routing
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
| Previous Lesson | Next Lesson |
|---|---|
| Create, Retrieve, Update, Delete APIs | URL Routing |
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.