50 days of learning APIs

📅 Table of Contents

  1. Day 1 - Introduction & Setup
  2. Day 2 - Library website & API
  3. Day 3 - Todo website & frontend and back-end API Integration
  4. Day-4 - Permissions in Django REST Framework
  5. Day-5 - User Authentication Methods in Django REST Framework

Day-1 of Learning APIs

| Published by Sudip Shrestha(Author)

At the beginning of my journey to learn APIs, I explored various resources. Mostly, I prefer to learn from books, which is why I searched online for a book and found one titled Django for APIs by William S. Vincent. The reasons for me to choose this book were:

  • I was already interested in Django and the scope of this book focused on Django.
  • This book was specifically written to help beginners, addressing the lack of good resources available for developers new to the Django REST Framework.
  • It also includes many projects, and the author has made the code publicly available on GitHub (in case reader couldn't solve it)

LEARNING:

I found that in recent years an "API-first" approach has emerged as arguably the dominant paradigm in web development. This approach involves formally seperating the back-end from the front-end.

This paradigm of web-developement is "Future proof" because a backend API can be consumed by any JavaScript front-end(when the current front-end Framework eventually replaced by even newer ones in the years to come, the back-end API can remain the same) not only that when one expand from web to mobile app the change is only the front-end part we don't have to redesign the whole backend architecture for the newer frontend by simply attaching with the API.

Serilization

A serializer translates data into a format that is easy to consume over the internet, typically JSON, and is displayed at an API endpoint.

Why Serializers are Important?

  • APIs talk using JSON (or other formats).
  • Django models are Python classes, not JSON.
  • Serializers translate between these two worlds.

Types of Serializers in DRF

Type Meaning
serializer.serilizers manually define field
serializer.ModelSerilizer automatically define a field based on model

    What Happens
  • Serialization Python object ➔ JSON (send to client)
  • Deserialization JSON ➔ Python object (receive from client)
  • Validation Check if input data is valid (correct types, formats)
  • Saving If valid, create/update the model in the database
  • Generics

    In Django REST Framework (DRF), generics are a set of views that provide common functionality for working with API endpoints. They simplify the creation of common API views, such as listing, creating, retrieving, updating, or deleting resources. DRF provides a range of generic views for these operations, allowing developers to quickly create RESTful APIs without writing repetitive code. What are Generics in DRF? Generics are class-based views that come pre-built with common behaviors for handling standard database operations like retrieving, updating, and deleting model instances. These views are built on top of DRF's APIView and provide convenient methods to simplify CRUD operations. There are several generic views provided by DRF, and you can use them directly or extend them to meet your needs. Types of Generics in DRF Here are the main generic views available in DRF: ListCreateAPIView: Used for displaying a list of model instances and creating new ones. Provides functionality for GET (list of objects) and POST (create new object). RetrieveUpdateDestroyAPIView: Used for retrieving, updating, and deleting individual model instances. Provides functionality for GET (retrieve object), PUT/PATCH (update object), and DELETE (delete object).
    1. ListAPIView:
    2. Used for displaying a list of model instances. Provides functionality for the GET method (list objects), but doesn't support creating new objects.
    3. CreateAPIView:
    4. Used for creating new model instances. Provides functionality for the POST method (create object), but doesn't support listing or modifying objects.
    5. RetrieveAPIView:
    6. Used for retrieving a single model instance. Provides functionality for the GET method (retrieve object), but doesn't support creating or modifying objects.
    7. DestroyAPIView:
    8. Used for deleting a single model instance. Provides functionality for the DELETE method (delete object), but doesn't support listing or creating objects.
    9. UpdateAPIView:
    10. Used for updating an existing model instance. Provides functionality for PUT/PATCH (update object), but doesn't support listing or creating objects.

    Day-2 of Learning APIs

    | Published by Sudip Shrestha(Author)

    1. Installed django rest-framework

    2. 
      pip install djangorestframework
                      
    3. REST_FRAMEWORK Settings


    4. You can define a REST_FRAMEWORK dictionary in your settings.py file to customize how DRF behaves across your entire project.
      
      # settings.py
      REST_FRAMEWORK = {
          'DEFAULT_PERMISSION_CLASSES': [
              'rest_framework.permissions.AllowAny',
          ],
          'DEFAULT_AUTHENTICATION_CLASSES': [
              'rest_framework.authentication.SessionAuthentication',
              'rest_framework.authentication.BasicAuthentication',
          ],
      # Optional: Pagination
          'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
          'PAGE_SIZE': 10,
      }
      
                        
                        

      1. DEFAULT_PERMISSION_CLASSES

      This sets the default permission policy for your API views.

      Examples:

      • 'rest_framework.permissions.AllowAny': Anyone can access the API.
      • 'rest_framework.permissions.IsAuthenticated': Only authenticated users can access.
      • 'rest_framework.permissions.IsAdminUser': Only admin users can access.
      • 'rest_framework.permissions.DjangoModelPermissions': Uses Django's built-in model permissions.

      2. DEFAULT_AUTHENTICATION_CLASSES

      This sets how DRF will authenticate users.

      Common options:

      • 'rest_framework.authentication.SessionAuthentication': Uses Django sessions (for browser users).
      • 'rest_framework.authentication.BasicAuthentication': HTTP Basic Auth (not safe for production unless HTTPS).
      • 'rest_framework.authentication.TokenAuthentication': For token-based auth (requires rest_framework.authtoken).
      • 'rest_framework_simplejwt.authentication.JWTAuthentication': For JWT tokens (third-party).

      3. DEFAULT_PAGINATION_CLASS and PAGE_SIZE

      Used to paginate large lists of data automatically.

      Example:

      'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
      'PAGE_SIZE': 10

      This splits large API responses into pages. DRF adds navigation links like:

      {
        "next": "http://.../api/posts/?page=2",
        "previous": null,
        "results": [...]
      }

      Other pagination classes:

      • LimitOffsetPagination
      • CursorPagination

      Optional Settings You Might Use Later:

      • Throttle settings (limit requests per user/IP)
      • Versioning (support multiple API versions)
      • Exception handling customization
      • Renderers (like JSON or browsable API UI)

      Creating Views and Serializers for API

      1. serializers.py

      In serializers.py, you'll define how the data will be serialized (converted into JSON format). A serializer is similar to a Django Form or ModelForm.

      
      # api/serializers.py
      from rest_framework import serializers
      from .models import Post
      
      class PostSerializer(serializers.ModelSerializer):
          class Meta:
              model = Post
              fields = '__all__'  # Serialize all fields of the Post model
      

      Explanation:

      • ModelSerializer: This is the most common serializer that automatically generates fields based on the Django model.
      • fields = '__all__': This indicates that you want to serialize all the fields in the model. You can also specify specific fields, e.g., ['title', 'content'].

      2. views.py

      In views.py, you'll define the API views. DRF provides several ways to create views, including APIView, viewsets, and generic views.

      Option 1: Using ViewSets (Recommended for simplicity)

      ViewSets allow you to handle basic CRUD operations automatically.

      
      # api/views.py
      from rest_framework import viewsets
      from .models import Post
      from .serializers import PostSerializer
      
      class PostViewSet(viewsets.ModelViewSet):
          queryset = Post.objects.all()  # Query to get all posts
          serializer_class = PostSerializer  # Specify the serializer to use
      
      • ModelViewSet: Automatically provides implementations for CRUD operations (Create, Read, Update, Delete).

      Option 2: Using APIView (Custom behavior)

      If you need more custom behavior, you can use APIView to manually define the logic for each method (GET, POST, PUT, DELETE).

      
      # api/views.py
      from rest_framework.views import APIView
      from rest_framework.response import Response
      from rest_framework import status
      from .models import Post
      from .serializers import PostSerializer
      
      class PostList(APIView):
          def get(self, request, format=None):
              posts = Post.objects.all()  # Fetch all posts
              serializer = PostSerializer(posts, many=True)  # Serialize the data
              return Response(serializer.data)  # Return as JSON
      
          def post(self, request, format=None):
              serializer = PostSerializer(data=request.data)  # Get data from request
              if serializer.is_valid():
                  serializer.save()  # Save to database
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
      • get(): Retrieves data.
      • post(): Creates new data.

      3. URLs Setup

      Once your views are defined, you need to wire them up in the URLs file (urls.py).

      Using ViewSet (DRF Router)

      With viewsets, DRF provides a router that automatically maps the views to URLs.

      
      # api/urls.py
      from django.urls import path, include
      from rest_framework.routers import DefaultRouter
      from .views import PostViewSet
      
      router = DefaultRouter()
      router.register(r'posts', PostViewSet)  # Register PostViewSet for 'posts' endpoint
      
      urlpatterns = [
          path('', include(router.urls)),  # Includes all routes from the router
      ]
      

      Using APIView

      If you're using APIView, manually create URL mappings.

      
      # api/urls.py
      from django.urls import path
      from .views import PostList
      
      urlpatterns = [
          path('posts/', PostList.as_view(), name='post-list'),  # Map to PostList class
      ]
      

      4. Example of Testing the API

      Once everything is set up, you can test the API by running the development server:

      
      python manage.py runserver
      

      Visit http://127.0.0.1:8000/api/posts/ to see the list of posts (if you're using PostViewSet) or http://127.0.0.1:8000/api/posts for the APIView.

    Day-3 of Learning APIs

    | Published by Sudip Shrestha(Author)

    What I Learned About Django REST Framework (DRF) and API Integration

    • DRF returns data in JSON format
      Example:
      [
        { "id": 1, "title": "Task 1", "body": "Learn Django" },
        { "id": 2, "title": "Task 2", "body": "Learn React" }
      ]
    • Django automatically adds an id field
      This helps React identify each item using a unique key when rendering a list.
    • You use HTTP GET to access data from DRF
      Called using: axios.get('http://127.0.0.1:8000/api/')
    • API endpoint design matters
      Keeping it clean like /api/ helps frontend-backend communication.
    • CORS must be enabled
      React (on port 3000) and Django (on 8000) are separate origins, so CORS must be set using: django-cors-headers
    • API integration keeps content dynamic
      React doesn't hardcode data — it fetches the live list from Django.
    • DRF (backend) and React (frontend) work together
      DRF handles logic/data, React handles UI — and APIs connect them.

    What is CORS?

    CORS (Cross-Origin Resource Sharing) is a security feature enforced by web browsers. It determines whether a web application running on one origin (domain) is permitted to request resources from a different origin.

    Purpose: Prevent unauthorized cross-domain requests for security.

    Common Headers:

    • Access-Control-Allow-Origin
    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers

    Example: A frontend hosted on https://example.com trying to access data from https://api.othersite.com requires CORS headers from the API server.


    How to Handle CORS in Django

    Use the django-cors-headers package:

    1. Install the package

    pip install django-cors-headers

    2. Add to INSTALLED_APPS in settings.py

    'corsheaders',

    3. Add middleware (near the top)

    'corsheaders.middleware.CorsMiddleware',

    4. Allow all origins (for development)

    CORS_ALLOW_ALL_ORIGINS = True

    5. Or allow specific origins (recommended for production)

    
    CORS_ALLOWED_ORIGINS = [
        "http://localhost:3000",
        "https://your-frontend.com",
    ]
      

    Note: Only browser-based requests are affected by CORS. Server-to-server requests don't require it.

    Day-4 of Learning APIs

    | Published by Sudip Shrestha(Author)

    Today I Learned: Custom Permissions in Django REST Framework

    Django REST Framework ships with several out-of-the-box permission settings that we can use to secure our API. These permissions can be applied at different levels:

    • Project-level: Set globally via settings.py
    • View-level: Applied to specific views or viewsets
    • Model-level: Enforced per-object using custom logic

    Today, I learned how to create my own custom permission for my current project — a Blog site. I implemented a permission that ensures only the author of a blog post has the ability to update or delete it.

    What This Means

    By writing a custom permission class and attaching it to my viewset, I've added a layer of security to make sure that users cannot modify blog posts that they don't own. This enhances data integrity and user accountability in my app.

    Custom Permissions in Django REST Framework (DRF)

    What Are Custom Permissions?

    Custom permissions in DRF let you define fine-grained access control for your API endpoints, going beyond the built-in permissions like IsAuthenticated or IsAdminUser.

    How BasePermission Works

    • BasePermission is an abstract class you subclass to create custom permissions.
    • has_permission(self, request, view): checks general (view-level) access.
    • has_object_permission(self, request, view, obj): checks object-specific access (e.g., for retrieve/update/delete).
    • DRF calls has_permission() first, then has_object_permission() if the view is detail-based.

    How to Create a Custom Permission

    
            # app_name/permissions.py
            from rest_framework.permissions import BasePermission
            
            class IsOwnerOrReadOnly(BasePermission):
                def has_object_permission(self, request, view, obj):
                    if request.method in ['GET', 'HEAD', 'OPTIONS']:
                        return True
                    return obj.owner == request.user
              

    How to Use a Custom Permission in a View

    
            # app_name/views.py
            from rest_framework import viewsets
            from .models import Article
            from .serializers import ArticleSerializer
            from .permissions import IsOwnerOrReadOnly
            
            class ArticleViewSet(viewsets.ModelViewSet):
                queryset = Article.objects.all()
                serializer_class = ArticleSerializer
                permission_classes = [IsOwnerOrReadOnly]
              

    Combining With Built-in Permissions

    
            from rest_framework.permissions import IsAuthenticated
            
            class ArticleViewSet(viewsets.ModelViewSet):
                ...
                permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
              

    Optional: Set as Global Default in settings.py

    
            REST_FRAMEWORK = {
                'DEFAULT_PERMISSION_CLASSES': [
                    'rest_framework.permissions.IsAuthenticated',
                    'your_app.permissions.IsOwnerOrReadOnly',
                ]
            }
              

    You can build more advanced permissions using custom logic inside the permission class.

    Day-5 of Learning APIs

    | Published by Sudip Shrestha(Author)

    🔐 Introduction to User Authentication

    User authentication is the process of verifying the identity of a user who is trying to access a system. It ensures that only registered and authorized users can access certain features, data, or services within a web or mobile application.

    Since HTTP is stateless, servers cannot remember user sessions across multiple requests. To overcome this, authentication mechanisms are used to identify users in each interaction with the server.

    Common user authentication actions include:

    • Sign Up – Creating a new user account
    • Log In – Verifying user credentials to gain access
    • Log Out – Ending an authenticated session

    Web applications and APIs support various authentication methods such as Basic Auth, Session Auth, Token Auth, JWT, and OAuth2, each with their own use cases and security considerations.

    User Authentication Methods in Django REST Framework

    1. Basic Authentication

    Concept: Sends the username and password in every HTTP request using the Authorization header.

    Workflow:

    1. Client sends a request.
    2. Server responds with 401 Unauthorized.
    3. Client resends the request with encoded credentials.
    4. Server checks and responds with 200 OK or 403 Forbidden.

    Pros: Simple setup.

    Cons: Insecure unless HTTPS is used. Credentials sent on every request.

    REST_FRAMEWORK = {
                'DEFAULT_AUTHENTICATION_CLASSES': [
                    'rest_framework.authentication.BasicAuthentication',
                ]
            }

    2. Session Authentication

    Concept: Credentials are sent once; then a session ID is stored in a cookie for further requests.

    Workflow:

    1. User logs in with username and password.
    2. Server creates a session object and returns a session ID cookie.
    3. Browser sends this cookie on every request.
    4. Server validates the session ID and grants access.

    Pros: More secure and efficient than Basic Auth for web apps.

    Cons: Not suitable for APIs across multiple devices or clients.

    REST_FRAMEWORK = {
                'DEFAULT_AUTHENTICATION_CLASSES': [
                    'rest_framework.authentication.SessionAuthentication',
                ]
            }

    3. Token Authentication

    Concept: User gets a token after login and includes it in the header of every request.

    Workflow:

    1. User logs in with credentials.
    2. Server returns a token.
    3. Client sends token with each request using Authorization: Token <token>.

    Pros: Stateless, secure, works for APIs across platforms.

    Cons: Requires token storage and revocation handling.

    4. JWT (JSON Web Token)

    Concept: A self-contained token with user info and expiry, sent with every request.

    Workflow:

    1. User logs in and receives a JWT.
    2. Client sends JWT in Authorization: Bearer <jwt> header.
    3. Server verifies and decodes the token.

    Pros: Stateless, scalable, secure with expiry and compact structure.

    Cons: Cannot be revoked easily without extra tools.

    5. OAuth 2.0

    Concept: User logs in through a third-party (like Google), receives a token used to access protected resources.

    Workflow:

    1. User authenticates through a provider (Google, Facebook, etc.).
    2. Provider returns an access token.
    3. Client uses this token to authenticate or fetch data.

    Pros: Very secure, no handling of credentials, suitable for social logins.

    Cons: Complex to set up, external dependency.

    Summary Table

    Authentication Type Stateful? Secure? Use Case
    Basic Auth No Only with HTTPS Testing or internal APIs
    Session Auth Yes Yes Django web apps
    Token Auth No Yes APIs across platforms
    JWT No Yes (with expiry) Modern APIs
    OAuth 2.0 No Yes Social login, external APIs

    ***HAPPY ENDING***