Skip to content

Writing Endpoints in Django Rest Framework (DRF)

Berkay Bilen edited this page May 8, 2025 · 3 revisions

Creating an Endpoint in Django REST Framework (DRF)

To create an endpoint in a Django REST Framework (DRF) project, follow these steps:


0. Find Which App to Work on

Every React project has multiple apps inside it. In our case these are accounts, api, foods and project holds setup for the whole project. In this example we will work on foods.

/backend
  /accounts
    ...
    views.py
    urls.py
  /api
    ...
    views.py
    urls.py
  /foods
    ...
    views.py
    urls.py
  /project
    settings.py
    urls.py
    wsgi.py
    asgi.py
  manage.py

1. Write the Endpoint in views.py

Create a view that inherits from APIView. Define HTTP method handlers (get, post, etc.) as methods.

Also don't forget to add different HTTP status' in your response. For example if no record is found return an error message so that client will understand there is no data, etc. This is not the best example but you got the point.

You can find information about HTTP codes at the end of this document.

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from .models import FoodEntry
from .serializers import FoodEntrySerializer

class FoodCatalog(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """
        GET /foods/get_foods
        Returns all FoodEntry instances from the database.
        - 200 OK if any foods exist
        - 404 Not Found if no entries are available
        Requires JWT token in Authorization header.
        """
        foods = FoodEntry.objects.all()

        if foods.exists():
            serializer = FoodEntrySerializer(foods, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response(
                {"detail": "No food entries found."},
                status=status.HTTP_404_NOT_FOUND
            )

2. Set permission_classes

Use the permission_classes attribute to define access control.

  • If the method is required to be user authentication(that means if a user must be logged in for that functionality you must use IsAuthenticated.
permission_classes = [AllowAny]  # or [IsAuthenticated]

3. Add the Endpoint's URL in the App's urls.py

Map the view to a route in your Django app's urls.py file (e.g., inside the foods app):

from django.urls import path
from .views import FoodCatalog

urlpatterns = [
    path("get_foods", FoodCatalog.as_view(), name="get_foods"),
]

4. Include the App's URLs in the Project's urls.py

In your project's main urls.py, the app’s URLs is included under a path prefix, such as `foods/'.

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", include("api.urls")),
    path("users/", include("accounts.urls")),
    path("users/", include("django.contrib.auth.urls")),
    path("foods/", include("foods.urls")),
]

This means the full URL path to your endpoint will be:

http://localhost:8081/foods/get_foods

The URL must include the app name (foods/) because all app-level URLs are merged into the main project under their designated path prefixes.


5. Test the Endpoint

Start the Django server and test the endpoint using curl or a browser.

curl http://localhost:8081/foods/get_foods

If running inside a container, ensure the correct port mapping is applied (e.g., -p 8081:8081).

Models

Here is an example model class that you can find in repo. Models are the Python classes that stands for DB tables, that we add fields, their types, and other attributes and constraints. If you need to add any seperate table object in your endpoint you can create it as follows, then we will handle DB migrations.

from django.db import models

class FoodEntry(models.Model):
    name = models.CharField(max_length=100)
    category = models.CharField(max_length=50)
    serving_size = models.PositiveIntegerField(help_text="In grams")
    calories_per_serving = models.FloatField()
    protein_content = models.FloatField()
    fat_content = models.FloatField()
    carbohydrate_content = models.FloatField()
    allergens = models.JSONField(default=list, blank=True)  # e.g., ["Peanuts", "Gluten"]
    dietary_options = models.JSONField(default=list, blank=True)  # e.g., ["Vegan", "Vegetarian"]
    nutrition_score = models.PositiveIntegerField()
    image_url = models.URLField(blank=True)

    def __str__(self):
        return self.name

6. Serializers

Here is an example serializer that maps helps mapping raw data into Python object, which is useful when we convert request parameters into a model object so that we can use ORM to use it in database operations.

from rest_framework import serializers
from .models import FoodEntry

class FoodEntrySerializer(serializers.ModelSerializer):
    class Meta:
        model = FoodEntry
        fields = '__all__'  # or list only specific fields

7. ORMs

Here are the exampe ORM methods that you can used to fetch, delete, or insert data into database that will probably be used in your services or APIs mostly.

# fetches all the data 
foods = FoodEntry.objects.all() 

# fetches all the data with a constraint with a field etc. for example here all rows which has category fruit will be fetched.
fruits = FoodEntry.objects.filter(category="Fruit") 

# here is basically an insertion into DB.
FoodEntry.objects.create(
    name="Avocado",
    category="Fruit",
    serving_size=100,
    calories_per_serving=160,
    protein_content=2.0,
    fat_content=15.0,
    carbohydrate_content=9.0,
    allergens=[],
    dietary_options=["Vegan", "Vegetarian"],
    nutrition_score=92,
    image_url="https://example.com/avocado.jpg"
)

Common HTTP Status Codes in REST APIs

Below are the five most frequently used HTTP status codes, especially in Django REST Framework APIs:


1. 200 OK

  • Meaning: The request was successful.
  • Use case: Standard response for successful GET, PUT, or DELETE operations.
  • Example: Returning a list of food entries.

2. 201 Created

  • Meaning: A new resource was successfully created.
  • Use case: After a successful POST request (e.g., creating a new user or food item).
  • Example: Returning the newly created food entry.

3. 400 Bad Request

  • Meaning: The request is malformed or missing required data.
  • Use case: When the client sends invalid JSON or fails validation checks.
  • Example: Missing name field in the payload.

4. 401 Unauthorized

  • Meaning: Authentication is required or token is invalid.
  • Use case: JWT token is missing or expired.
  • Example: User attempts to access a protected endpoint without logging in.

5. 404 Not Found

  • Meaning: The requested resource could not be found.
  • Use case: Trying to retrieve or delete a food entry that doesn't exist.
  • Example: GET /foods/999 when ID 999 doesn't exist.
Clone this wiki locally