Endpoints for Models0%

Endpoints for Models

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

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:

  1. 1
    Always use lowercase plural nouns: /api/v1/customers/ (not /Customer or /getCustomer).
  2. 2
    Represent hierarchies naturally: /api/v1/projects/{id}/tasks/ indicates tasks belonging to a specific project.
  3. 3
    Limit nesting depth: Avoid nesting deeper than 2 levels (/orgs/1/projects/2/tasks/3/comments/4 is an anti-pattern!). Flatten deep children: /api/v1/tasks/{task_id}/comments/.
  4. 4
    Use 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

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext