[Go to site: main page, start]

0% found this document useful (0 votes)
25 views146 pages

Python Microservices Architecture Guide

Microservices architecture is a software development approach where applications are structured as independent services focused on specific business functions, allowing for independent development, deployment, and scaling. This architecture contrasts with monolithic applications, which are tightly coupled and can become complex as they grow. Microservices are particularly beneficial for large-scale web, cloud-based, e-commerce, banking, and IoT applications, offering advantages such as resilience, scalability, and technology diversity, but also introduce challenges like service communication, deployment management, and security.

Uploaded by

sahilpingale3003
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views146 pages

Python Microservices Architecture Guide

Microservices architecture is a software development approach where applications are structured as independent services focused on specific business functions, allowing for independent development, deployment, and scaling. This architecture contrasts with monolithic applications, which are tightly coupled and can become complex as they grow. Microservices are particularly beneficial for large-scale web, cloud-based, e-commerce, banking, and IoT applications, offering advantages such as resilience, scalability, and technology diversity, but also introduce challenges like service communication, deployment management, and security.

Uploaded by

sahilpingale3003
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Microservices using Python

Introduction to Microservices
❖ What Are Microservices?

● Microservices architecture is an approach to software development where an


application is structured as a collection of small, independent, and loosely coupled
services.
● Each microservice focuses on a specific business function and can be developed,
deployed, and scaled independently.
● for example, handling user authentication, processing orders, or managing payments.
● In contrast to traditional monolithic applications, where all the functionality resides in a
single codebase, microservices allow each component to operate independently with its
own codebase, database, and deployment pipeline.
❖ Microservices architecture
Microservice Name Purpose / Function Example

Authentication Service Manages login, signup, user Login with email/OTP


roles, and tokens

User Profile Service Handles user information and View/update profile


preferences

Product/Content Service Manages data related to Product listings, videos,


products or content posts

Cart/Order Service Processes shopping carts or Add to cart, checkout


orders

Payment Service Handles payments, refunds, and Pay with card, UPI, wallet
invoices

Notification Service Sends email, SMS, or push “Order placed” alert


notifications
Search Service Provides search functionality Product or document
search

Review/Feedback Manages ratings and User reviews


Service comments

Inventory Service Tracks stock levels or Update stock after


available resources purchase

Analytics Service Collects data for reports and Daily active users, sales
insights stats

Gateway Service (API Acts as a single entry point for Routes requests to the
Gateway) users right service
Applications that Need Microservices
1. Large-Scale Web Applications
○ When an app has many features and a large number of users.
○ Example: Amazon, Netflix, Flipkart, YouTube
○ Each function (search, recommendation, payment, etc.) is built as a separate microservice.

2. Cloud-Based Applications
○ Microservices work very well with cloud platforms (AWS, Azure, Google Cloud).
○ Easy to deploy, scale, and manage each service independently.

3. E-Commerce Applications
○ Different modules like user management, catalog, payment, and orders can run separately.
○ Makes the system more reliable and flexible.

4. Banking and Financial Systems


○ Each microservice can handle one area such as account management, transactions, or
security.
○ Improves reliability and makes it easier to maintain regulatory compliance.
5. IoT (Internet of Things) Applications
○ Devices send a lot of data and microservices help to manage and process that data
in parallel.
○ Example: Smart home or smart city platforms.

6. Enterprise or SaaS Applications


○ Companies that offer software-as-a-service (SaaS) prefer microservices for easy
updates and multi-tenant support.
○ Example: CRM systems like Salesforce, Microsoft Dynamics, etc.
Example: E-commerce Application (Built in Python)

Let’s imagine you are building an e-commerce platform like “ShopEase” using Python microservices.

The system has the following independent services:

1. User Service – Manages user registration, login, and authentication.

2. Product Service – Manages product catalog and inventory.

3. Payment Service – Handles payment processing.

4. Notification Service – Sends emails or SMS notifications.


❖ Monolithic architecture
● Monolithic architecture is a software design model where all functions of an application are built
as a single, self-contained unit with one codebase.
● This makes it simple for smaller
applications, as components are tightly
coupled and communicate directly, but it
can become complex and difficult to
update as the application grows.
● For modifications, the entire application
must be recompiled, tested, and deployed,
which can cause performance issues and
slower development cycles in larger systems.
❖ Monolithic And Microservices Architecture
❖ Monolithic vs Microservices Architecture
Aspect Monolithic Architecture Microservices Architecture
Structure
Single, unified codebase handling all modules Multiple small, independent services
Deployment Each service can be deployed
Entire application is deployed as one unit independently
Scalability Scales the whole app even if one module needs Individual services can be scaled based on
it demand
Technology Stack
Usually restricted to one tech stack Each service can use different technologies
Fault Isolation
A bug in one part can crash the entire system Failures are isolated to individual services
Development Teams
Large, centralized teams Smaller, autonomous teams per service
Speed of Updates Slow—any change requires redeploying Fast—services can be updated
everything independently
Separate services for “Product Catalog,”
Example: A single e-commerce app handling products, “Order Management,” “Payment
payments, and orders together. Gateway,” etc.
❖ Characteristics and Advantages of Microservices

1. Independent and Autonomous Services


Each microservice is a self-contained unit that performs a specific business task.

For example:
● User Service only manages user data and authentication.

● Payment Service processes payments independently.


If you need to fix a bug in the Payment Service, you can do so without redeploying
the entire system.
# payment_service.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@[Link]('/pay', methods=['POST'])
def pay():
data = [Link]
# Process payment here...
return jsonify({"status": "success", "transaction_id": "TXN-00987"})
if __name__ == '__main__':
[Link](port=5002)
2. Loosely Coupled

Each service interacts only through APIs (not by sharing databases or code).
This means changes inside one service do not break others, as long as the API contracts remain the same.

● The Checkout Service calls the Payment Service using its REST API.
● The Payment Service doesn’t need to know how the Checkout Service works internally.

import requests # checkout_service.py

def checkout(order):

payment_response = [Link](

"[Link]

json={"order_id": order["id"], "amount": order["total"]}

).json()

return payment_response

If the Payment Service changes its internal logic (say, switching from Stripe to PayPal), the Checkout Service
doesn’t need to change , as long as the API stays consistent.
3. Decentralized Data Management
Each microservice owns its own database.
There’s no single shared database ,this keeps services independent and avoids data coupling.

Example: Service Database Description

User Service users_db Stores user credentials and


profiles

Product products_db Stores product info and


Service stock

Payment payments_d Stores payment history


Service b

Notification notifications Stores email logs


Service _db

So, if the Payment Service database crashes, it won’t affect the others.
4. Independent Deployment
Each service can be built, tested, and deployed separately.
For example:
● You can deploy the Notification Service update without touching the Payment Service.

● You can use Docker containers to deploy each service independently.


Example (Docker Concept):
docker build -t user-service:v2 .
docker build -t payment-service:v3 .
docker-compose up -d
Docker allows developers to run applications anywhere ,regardless of the operating
system or environment by packaging everything the app needs (code, libraries,
dependencies) into a container.
5. Scalability
You can scale individual services based on demand.

Example:
If your Payment Service is getting heavy traffic during a sale event, you can run more instances of just that service:

kubectl scale deployment payment-service --replicas=10

Other services (like Notification or Product) can stay at 2 replicas.


This saves resources and boosts performance.

6. Resilience and Fault Isolation


If one microservice fails, the others continue to run.

Example:

● If the Notification Service (email sending) fails, users can still browse products and make purchases.

● Later, you can reprocess failed notifications separately.


This is possible because services are isolated one failure doesn’t bring down the entire system.
7. Technology Diversity
Each team can choose the best tool or framework for their service.

Example:
Service Technology Reason

User Service Django + PostgreSQL Strong authentication and ORM

Product Service FastAPI + MongoDB High performance and NoSQL

Payment Service Flask + MySQL Lightweight and transactional

Notification Service Python + Redis Queue Asynchronous messaging

Python makes this easy, as you can mix frameworks and still connect via REST APIs.
8. Continuous Delivery and DevOps Friendly
Because services are small and independent, you can quickly:

● Write automated tests,

● Deploy changes frequently, and Roll back faulty services easily.


Only the payment service gets redeployed, not the whole system.
Real-World Examples and Case Studies

1. E-Commerce Platform API (e.g., Amazon / Flipkart Clone)


Overview:

An e-commerce system typically includes users, products, carts, orders, and payments all interacting through
APIs.
Django REST Framework can power such a backend, allowing mobile and web apps to communicate with the
server.

Key Features:

● User Registration & Authentication (using DRF’s JWT or Token Authentication)


● Product Catalog APIs (GET: list products, POST: add products)
● Shopping Cart and Orders (POST: create order, PUT: update order, DELETE: cancel order)
● Payment Integration (communicating with third-party payment gateways like Stripe or Razorpay)

Real-World Example:- Amazon and Flipkart use internal REST APIs for their mobile apps and web front ends, all
managed behind API Gateways for load balancing, routing, and monitoring.
2. Student Management System (Education Domain)

Overview:
A web and mobile application for managing school or university data like students, teachers, subjects, and grades
using DRF as the backend.

Key Features:

● Student APIs: Add, update, delete student records.

● Teacher APIs: Manage teacher profiles and subjects.

● Result APIs: Allow teachers to update and students to view results.

● Role-based Access: Teachers and admins have different permissions.

Real-World Example:
Many educational ERPs (like Google Classroom, Canvas, or Blackboard) use similar RESTful
backends to power dashboards, mobile apps, and grading systems.
3. Ride-Sharing Application (e.g., Uber / Lyft Clone)
Overview:

A complex system where multiple microservices (Driver Service, Rider Service, Trip Service, Payment Service)
communicate through APIs managed via an API Gateway.

Key Features:

● User Registration (Riders & Drivers) using DRF Authentication.

● Trip Management APIs: Create, update, or cancel rides.

● Real-Time Updates: APIs send data about trip status and driver location.

● Payments & Ratings: APIs for processing payments and managing reviews.

Real-World Example:

Uber and Lyft use thousands of microservices managed by API gateways to ensure high performance
and security across multiple platforms.
4. Music Streaming API (e.g., Spotify / YouTube Music)
Overview:

A backend service that provides music, playlists, and user data through REST APIs.
DRF can be used to manage song catalogs, playlists, and streaming statistics.

Key Features:

● Song and Playlist APIs: Retrieve songs, create playlists, like/dislike tracks.

● User Profiles: Authentication, subscription, and preferences.

● Recommendations: Endpoint for personalized song suggestions.

● Analytics: Collecting usage data for reports or dashboards.

Real-World Example:- Spotify uses REST APIs internally and exposes developer APIs publicly, allowing
external apps to access music data, playlists, and analytics.
Challenges in Microservices Implementation (Python
Perspective)
Microservices solve many problems but they also introduce new complexities, especially when
implemented in Python.

1. Service Communication and Coordination


Key Challenges:

● Complex Inter-Service Communication:


Microservices interact over networks using APIs or messaging systems. This introduces latency, potential
message loss, and error-handling complexity.

● API Versioning:
Maintaining backward compatibility while evolving services is difficult.

● Distributed Transactions:
Ensuring data consistency across multiple services (e.g., user and order services) is challenging since
traditional ACID (Atomicity, Consistency, Isolation, and Durability) transactions don’t span multiple databases.
2. Deployment and Infrastructure Management
Key Challenges:
● Increased Operational Overhead:
Each service must be deployed, monitored, and scaled independently.
● Configuration Management:
Managing environment variables, secrets, and service discovery (e.g., IPs, ports) becomes complex.
● Container and Orchestration Complexity:
Using tools like Docker and Kubernetes adds flexibility but also steepens the learning curve.

3. Data Management and Consistency


Key Challenges:
● Decentralized Data Ownership:
Each microservice typically has its own database, which prevents cross service joins.
Eventual Consistency:
Data synchronization relies on asynchronous messaging and event-driven patterns.
● Data Duplication:
To avoid coupling, services often maintain local copies of shared data, creating synchronization issues.
4. Security and Access Control

Key Challenges:
● Distributed Authentication and Authorization:
Each service must securely verify requests, often requiring a central identity provider.
● Secure Communication:
Protecting APIs with SSL/TLS and managing certificates across multiple services.
Secret Management:
Storing and rotating API keys, credentials, and tokens securely.

5. Monitoring, Logging, and Debugging

Key Challenges:
● Distributed Observability:
It’s harder to trace a user request across multiple services.
● Centralized Logging:
Aggregating logs from dozens of services for analysis requires additional infrastructure (e.g., ELK
stack).
● Complex Root Cause Analysis:
Debugging issues across multiple services and environments is time-consuming.
6. Performance and Scalability
Key Challenges:
● Network Overhead:
Communication between services introduces latency compared to in-process function calls.
● Load Balancing:
Each service needs its own scaling and traffic routing strategy.
Bottlenecks:
One slow service can cascade failures across the system if not isolated properly.

7. Testing and Quality Assurance


Key Challenges:
● Integration Testing:
Verifying the behavior of multiple services together is harder than testing a monolith.
● Service Mocks and Stubs:
Unit tests must simulate dependencies, increasing test complexity.
End-to-End Testing:
Requires setting up an entire ecosystem of services, often using Docker Compose or test
orchestration tools.
8. Team Coordination and Governance

Key Challenges:
● Decentralized Development:
Multiple teams working independently can lead to inconsistent design patterns or duplicated functionality.
● Standardization:
Without strong governance, services may differ in logging, monitoring, or API conventions.
● Dependency Management:
Managing shared libraries, SDKs, and version compatibility across teams is non-trivial.

9. Cost and Resource Management


Key Challenges:
● Infrastructure Costs:
Each microservice consumes its own compute, memory, and networking resources.
● Operational Costs:
Maintaining CI/CD pipelines, monitoring, and scaling adds DevOps overhead.
● Inefficient Scaling:
Poorly designed services may scale independently but inefficiently, wasting resources.
10. Migration and Legacy Integration
Key Challenges:
● Splitting a Monolith:
Refactoring existing monolithic applications into microservices is time-consuming and risky.

● Backward Compatibility:
Ensuring new microservices can communicate with legacy systems.

● Incremental Rollout:
Managing partial deployments and fallbacks during migration.
Introduction to Django REST Framework
(DRF):
What is an API?
● Stands for Application Programming Interface. Basically ,Two machines use it to communicate with
each other.
● An API is used by two applications trying to communicate with each other over a network or
Internet.
● The API acts as a mediator between Django and other applications. As you can see, other
applications can be from Android, iOS, Web apps, browsers, etc.
● The API’s main task is to receive data from other applications and provide them to the backend. This
data is usually in JSON format.
● APIs are programs that exist to transfer data between applications. They are responsible for cleaning
and formatting data correctly.

.
What are RESTful APIs?
● REST stands for Representational State Transfer. REST is an architecture on which we
develop web services. Web services can be understood as your device connects to the
internet.
● When you search for anything on Google or watch something on YouTube, these are web
services where your device is communicating to a server.
● When these web services use REST Architecture, they are called RESTful Web Services.
These web services use HTTP to transmit data between machines.
● A RESTful API acts as a translator between two machines communicating over a Web
service. This is just like an API but it’s working on a RESTful Web service. Web developers
program REST API such that server can receive data from applications.
● These applications can be web-apps, Android/iOS apps, etc. RESTful APIs today return
JSON files that can be interpreted by a variety of devices.
● The RESTful API will provide standardized data to all devices.
What is Django REST Framework?
DRF is an acronym for Django REST Framework. It’s used to develop REST APIs for Django. DRF is used to develop
RESTful APIs .

1. HTTP Request :- The process begins when a client (such as a web app, mobile app, or browser) sends an HTTP request to the
Django [Link] request usually contains user data or instructions (e.g., to retrieve, create, update, or delete data).

Eg. GET /api/students/


2. URL Patterns:- The request first goes through URL patterns ([Link]), which define which view should
handle the request.
Each URL pattern corresponds to a particular API endpoint

Eg . /students/ → StudentViewSet).

3. Views:- Once the request reaches the appropriate view, Django REST Framework processes it.
Views (or ViewSets) contain the business logic they decide what to do with the data:
○ Retrieve data from the database.
○ Create or update new records.
○ Delete data.
The view communicates with the model layer to read/write data as needed.
Eg:- A StudentViewSet retrieves data from the Student model using a serializer.

4. Models
● Models represent the structure of your database tables in Django.
● The view sends a query to the model to read or write data.
● The model then interacts directly with the database (in this diagram, MySQL) to fetch or modify data.
Eg. [Link]() #fetches all student records from the database.
5. Database (MySQL)

● The database stores all persistent data such as user information, posts, products, etc.

● Django’s ORM (Object Relational Mapper) converts Python objects into SQL queries that interact with the
database.

6. Response

● After the model returns the data, the view uses a serializer to convert it into a format like JSON or XML
that the client can understand.

● The response is then sent back to the client through the same route (view → URL → HTTP response).

Eg. [

{"id": 1, "name": "Alice", "age": 20},

{"id": 2, "name": "Bob", "age": 22}

]
Differences Between Django and Django REST Framework (DRF)
Feature / Aspect Django (Web Framework) Django REST Framework (DRF)

Purpose Used to build web applications Used to build RESTful APIs that
that render HTML pages for users. return data (usually JSON or
XML) for client applications.

Output Type Returns HTML or templates for Returns JSON/XML responses for
browser-based interaction. use by web, mobile, or external
apps.

Use Case Best for building traditional Best for backend APIs in mobile
websites or admin panels. apps, SPAs (React, Angular), or
microservices.

Communication Works mainly through Works through HTTP requests


server-rendered web pages. (GET, POST, PUT, DELETE) to
exchange structured data.

Views Uses Django Views Uses API Views / ViewSets that


(function-based or class-based) handle data serialization and
that render templates. return JSON responses.
No built-in serialization — must Has Serializers to automatically
Serialization manually convert data if needed. convert models/objects into
JSON/XML.

Basic user authentication via Advanced authentication (Token,


Authentication & Permissions sessions. OAuth2, JWT) and granular
permissions.

Designed to work directly with HTML Designed to interact with frontend


Frontend Interaction templates rendered on the server. frameworks or mobile apps
consuming APIs.

Provides regular HTML pages. Provides a Browsable API interface


Browsable Interface for testing endpoints easily.

Tight integration with Django ORM Extends Django ORM but focuses
Data Handling and templates for UI rendering. on data exchange via APIs, not UI
rendering.

HTML page displaying data. JSON response containing data.


Example Output

Django → Builds websites for human users (HTML-based).


What is a REST API?
A REST API (Representational State Transfer Application Programming Interface) is a way for
different systems (like web or mobile apps) to communicate with a server using the HTTP protocol.

It follows a set of rules and principles that make web services scalable, lightweight, and easy to use.

In a REST API:

● Each piece of data (like a user, product, or post) is treated as a resource.

● Resources are accessed using URLs (endpoints).

● Operations on these resources are done using standard HTTP methods.


Main HTTP Methods in REST API
HTTP Method Purpose / Action Example Endpoint Description

GET Retrieve (Read) data from the /api/students/ or Used to fetch data. It does not
server /api/students/1/ change anything on the server.

POST Create a new resource /api/students/ Used to send new data to the
server to create a record.

PUT Update an existing resource /api/students/1/ Used to replace an entire


(replace) resource with new data.

PATCH Partially update an existing /api/students/1/ Used to update specific fields


resource of a resource.

DELETE Delete a resource /api/students/1/ Used to remove a resource


from the server.
Installing DRF in an existing Django project
❖ Install DRF
Step 1: Create a Project Folder & Virtual Environment
mkdir myproject
cd myproject
python -m venv env
#Activate the virtual environment:
env\Scripts\activate myproject/
#Upgrade pip: ├── [Link]
pip install --upgrade pip ├── myproject/
│ ├── __init__.py
Step 2: Install Django and DRF │ ├── [Link]
│ ├── [Link]
pip install django djangorestframework │ └── [Link]
pip install django-filter markdown
Step 3: Create a Django Project
django-admin startproject myproject .
Step 4: Create a Django App (Optional for Future APIs)
python [Link] startapp myapp
#Folder structure now:
myproject/
├── myapp/
│ ├── migrations/
│ ├── __init__.py
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
Step 5: Add DRF to Installed Apps
Edit :- myproject/[Link]:
INSTALLED_APPS = [
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
# Your app
'myapp',
# DRF
'rest_framework',
]
Step 6: Configure DRF (Optional)
At the bottom of [Link], you can add:

REST_FRAMEWORK = {

'DEFAULT_PERMISSION_CLASSES': [

'rest_framework.[Link]', # APIs will be public by default

This is optional you can customize permissions, authentication, pagination later.

Step 7: Run the Server


python [Link] runserver
Visit: [Link] Your Django project is now running, and DRF is installed and
ready. You haven’t created any serializers or views yet, but the setup allows you to add APIs
anytime in the future.
Developing REST APIs with Django REST Framework:
[Link] MODELS :-

What is a Model?
In Django, a Model is a Python class that defines the structure of your database tables.
Each model maps to one table in your database, and each attribute of the model represents a field
(a column in that table).

Models define:
● What kind of data your app stores

● How different pieces of data relate to each other

Example: Blog Application


Let’s build a simple Blog API with Posts and Comments.
# blog/[Link]
from [Link] import models
from [Link] import User
class Post([Link]):
title = [Link](max_length=200)
content = [Link]()
author = [Link](User, on_delete=[Link], related_name='posts')
created_at = [Link](auto_now_add=True)
updated_at = [Link](auto_now=True)
def __str__(self):
return [Link]
class Comment([Link]):
post = [Link](Post, on_delete=[Link], related_name='comments')
author = [Link](max_length=100)
text = [Link]()
created_at = [Link](auto_now_add=True)
def __str__(self):
return f'’Comment by {[Link]} on {[Link]}'
Field Description

CharField Stores short text (titles, names, etc.)

TextField Stores longer text (e.g., content, comments)

ForeignKey Creates a one-to-many relationship (e.g., many


comments belong to one post)

DateTimeField(auto_now_ Automatically sets timestamp when object is created


add=True)

DateTimeField(auto_now= Updates timestamp every time the object is saved


True)

Applying Migrations
Once your models are defined, Django needs to create the corresponding tables in the database.

python [Link] makemigrations

python [Link] migrate


To see and manage your data easily in the Django admin panel:
# blog/[Link]
from [Link] import admin
from .models import Post, Comment
[Link](Post)
[Link](Comment)
2. CREATING SERIALIZERS

What is a Serializer?
A Serializer in DRF converts complex Django model instances (Python objects) into
JSON data that can be rendered in an API response and vice versa.

It acts as a bridge between your Django models (Python objects) and your API (JSON
format).
Create a new file called blog/[Link]:

from rest_framework import serializers


from .models import Post, Comment
class CommentSerializer([Link]):
class Meta:
model = Comment
fields = '__all__'
class PostSerializer([Link]):
# Nested serializer to include comments in post details
comments = CommentSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ['id', 'title', 'content', 'author', 'created_at', 'updated_at', 'comments']
Serializer Explanation

Concept Description

ModelSerializer Automatically generates fields from your model


fields = '__all__' Includes all model fields
read_only=True Prevents editing certain fields via API (e.g., nested
relationships)
Nested Serializer Allows one serializer to include another (for
relationships)

Example: JSON Output for Post


If you retrieve a Post instance, DRF automatically converts it into a JSON response:
Sample JSON Response "created_at": "2025-02-11T09:12:00Z",
{ "updated_at":
"2025-02-11T09:12:00Z"
"id": 1,
},
"title": "Understanding Django REST Framework",
{
"content": "This post explains how serializers work in DRF.",
"id": 11,
"author": 2,
"post": 1,
"created_at": "2025-02-10T14:30:00Z",
"author": 8,
"updated_at": "2025-02-10T14:45:00Z",
"text": "Thanks for this article!",
"comments": [
"created_at":
{ "2025-02-11T10:05:00Z",
"id": 10, "updated_at":
"post": 1, "2025-02-11T10:05:00Z"

"author": 5, }

"text": "Very useful explanation.", ]}


How the Flow Works
1. Client sends an HTTP request
Example: GET /posts/

2. View receives the request


View fetches data from the model.

3. Serializer converts data to JSON

4. View returns a DRF Response


Example JSON output:
Views in Django REST Framework
In DRF, views are responsible for:
● Receiving API requests (GET, POST, PUT, DELETE)
● Fetching or modifying model data
● Calling the serializer to convert data to JSON
● Returning an appropriate API response
In other words, Serializers format the data, but Views control how data is accessed.

Types of Views in Django REST Framework (DRF)


Django REST Framework provides multiple levels of abstraction for building APIs. These are the five major
categories:
1. Function-Based Views (FBVs)
2. Class-Based Views (APIView)
3. Mixins
4. Generic View Classes
5. ViewSets
Each type builds upon the previous one, providing more automation and requiring less boilerplate code
1. Function-Based Views (FBVs) in Django REST Framework
Function-Based Views (FBVs) are one of the simplest and most direct ways to build API endpoints in Django REST Framework. They rely on Python functions and
decorators to handle HTTP requests such as GET, POST, PUT, and DELETE. FBVs provide complete control over the request handling process and are an excellent
starting point for understanding how DRF processes API requests.

What Are Function-Based Views?


In DRF, an FBV is simply a Python function that receives an HTTP request object, performs some logic (such as retrieving or saving data), and returns a response object.
DRF enhances Django’s regular function-based views by adding support for features such as:

● JSON rendering

● Request data parsing

● HTTP method handling

● Serializer integration

● Proper API-friendly responses

To make a function behave as a DRF API endpoint, the @api_view decorator is used. This decorator ensures the view:

1. Accepts only the specified HTTP methods

2. Converts the incoming request to a DRF Request object

3. Returns responses in a consistent JSON format


Why Use Function-Based Views?
FBVs provide several important benefits:

1. Simplicity
They are easy to write, easy to read, and suitable for small or introductory projects.

2. Full Control
Because FBVs do not enforce a structure, developers have complete freedom over how requests are
processed.

3. Explicit Logic
All processing steps—fetching data, validating input, saving models—are visible directly in the function.
This makes the flow very transparent.

4. Ideal for Learning


FBVs are an excellent tool for beginners to understand how DRF handles requests, serialization,
validation, and response formatting.
How FBVs Work
An FBV typically:

1. Accepts a request
2. Determines the HTTP method
3. Reads or processes data
4. Serializes and returns the response

Example flow for a GET request:

● Client sends GET /api/posts/


● DRF hands over the request to the FBV
● The function fetches data from the database
● Serializer converts model objects to JSON
● FBV returns the JSON response

Example flow for a POST request:

● Client sends POST /api/posts/ with JSON payload


● FBV reads the data from [Link]
● Serializer validates and saves the object
● FBV returns the created object as JSON
Example of a Function-Based View

@api_view(['GET', 'POST'])
def post_list_create(request):
if [Link] == 'GET':
posts = [Link]()
serializer = PostSerializer(posts, many=True)
return Response([Link])

elif [Link] == 'POST':


serializer = PostSerializer(data=[Link])
if serializer.is_valid():
[Link]()
return Response([Link], status=status.HTTP_201_CREATED)
return Response([Link], status=status.HTTP_400_BAD_REQUEST)
Explanation of the Code:
● @api_view(['GET', 'POST']): Defines which methods the function supports.

● [Link]: Identifies the type of request (GET or POST).

● [Link](): Fetches all posts from the database.

● PostSerializer: Converts model instances to JSON.

● serializer.is_valid(): Validates incoming data.

● [Link](): Creates a new post record.

● Response(): Sends the final API response in JSON format.


When to Use Function-Based Views
FBVs are generally the right choice when:

● You need very simple and straightforward endpoints

● You are building a small API

● You want to understand the fundamental workings of DRF

● You require full manual control over each step of request handling

Limitations of Function-Based Views


While FBVs are simple and powerful, they also have limitations:

● More repetitive code compared to class-based or generic views

● Harder to scale as the project grows

● No built-in structure for reusability

● Not ideal for complex business logic

For large, production-level systems, developers often prefer Class-Based Views, Generic Views, or ViewSets.
2. Class-Based Views (CBVs) in Django REST Framework
Class-Based Views (CBVs) in Django REST Framework provide an object-oriented approach to building
API endpoints. They are more structured, reusable, and scalable than Function-Based Views (FBVs).
CBVs enable developers to organize request-handling logic inside classes, with each HTTP method
implemented as a separate class method (such as get(), post(), put(), and delete()).

In DRF, the foundational class for creating CBVs is APIView, which offers built-in features that make API
development cleaner and more maintainable.

What Is a Class-Based View?


A Class-Based View is a Python class that handles HTTP requests through methods. Instead of writing
procedural logic in a function, CBVs allow developers to encapsulate behavior inside a class. This
approach supports better organization, code reusability, and extension through inheritance.

In DRF, a CBV typically inherits from rest_framework.[Link].


Why Use Class-Based Views?
CBVs provide several advantages over Function-Based Views:

1. Clear Structure
Each HTTP method has its own method inside the class:

● get() handles GET requests

● post() handles POST requests

● put() handles PUT requests

● delete() handles DELETE requests

This separation improves readability and reduces clutter.

2. Reusability and Extensibility


CBVs enable you to:

● Inherit from base classes

● Override or customize only the behavior you need

● Extend functionality using mixins or generic views

This makes them ideal for medium and large projects.


3. Built-in DRF Features

APIView provides:

● Request parsing

● Authentication

● Permissions

● Throttling

● Exception handling

● JSON responses by default

These features are automatically available without additional code.

4. Better Organization

Keeping related logic inside a class promotes maintainability and makes complex APIs easier to manage.
How Class-Based Views Work in DRF
When a request arrives:
1. The URL route directs it to a CBV
2. DRF converts the raw request into a DRF Request object
3. Based on the HTTP method (GET, POST, etc.), the corresponding class method is executed
4. The method interacts with models and serializers
5. A DRF Response object is returned in JSON format
This workflow enhances structure and consistency.
Example of a Class-Based View (APIView)
class PostListCreateView(APIView):
def get(self, request):
posts = [Link]()
serializer = PostSerializer(posts, many=True)
return Response([Link])
def post(self, request):
serializer = PostSerializer(data=[Link])
if serializer.is_valid():
[Link]()
return Response([Link], status=status.HTTP_201_CREATED)
return Response([Link], status=status.HTTP_400_BAD_REQUEST
Explanation of the Code:
● The class inherits from APIView, making it a DRF class-based view.

● get() method handles listing all posts.

● post() method handles creating new posts.

● The view uses a serializer to convert data to and from JSON.

● A DRF Response() is returned to the client.


When to Use Class-Based Views
CBVs are ideal when:
● Your API requires clear structure
● Multiple related methods must be handled cleanly
● You plan to extend or reuse views
● Your project is growing and needs organized code

Limitations of Class-Based Views


While CBVs improve structure, they still require more manual coding than Generic Views or
ViewSets. For example:
● You must write the same boilerplate repeatedly (queryset, serializer, validation logic)
● Complex APIs may require additional layers (mixins, generics, viewsets)

For more automation, DRF provides Generic Views and ViewSets.


CRUD Operations using DRF
Django REST Framework is used to create web APIs very easily and efficiently. This is a wrapper
around the Django Framework. There are three stages before creating an API through the REST
framework,1) Converting a Model’s data to JSON/XML format (Serialization), 2)Rendering this data to
the view, and 3)Creating a URL for mapping to the views.
Install Django REST Framework
pip install djangorestframework

After installing the REST framework, go to [Link], and in INSTALLED_APPS add


‘rest_framework’ at the bottom
After installing the REST framework, go to [Link], and in INSTALLED_APPS add ‘rest_framework’ at the bottom.
INSTALLED_APPS = [
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'rest_framework',
]

Creating App for Django REST Framework

After installing the DRF and adding it to [Link], let's create an app using the command
python [Link] startapp api
A folder with the name api would have been registered by now.
Let’s add this app to INSTALLED_APPS and [Link] also. Now, add api urls in [Link]. In gfg_shopping.[Link],
In, [Link],
from [Link] import admin
INSTALLED_APPS = [ from [Link] import path, include

'[Link]', urlpatterns = [
path('admin/', [Link]),
'[Link]', path('api/', include('[Link]')),
]
'[Link]',

'[Link]',

'[Link]',

'[Link]',

'rest_framework',

'[Link]',

]
Creating Model in Django
Now let's create our model. We will create an item model. This model will be used by API to perform
the CRUD operations.

from [Link] import models

class Item([Link]):

category = [Link](max_length=255)

subcategory = [Link](max_length=255)

name = [Link](max_length=255)

amount = [Link]()

def __str__(self) -> str:

return [Link]

Now after our app gets ready let's create the serializer for our Item class.
Now let's create our [Link] file in the api folder and add the below code -

from [Link] import fields


from rest_framework import serializers
from .models import Item

class ItemSerializer([Link]):
class Meta:
model = Item
fields = ('category', 'subcategory', 'name', 'amount')

Create Views for Django

To render data into frontend, and handle requests from user, we need to create a view.
In Django REST Framework, we call these viewsets, so let’s create a view in
apis/[Link],
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Item
from .serializers import ItemSerializer
@api_view(['GET'])
def ApiOverview(request):
api_urls = {
'all_items': '/',
'Search by Category': '/?category=category_name',
'Search by Subcategory': '/?subcategory=category_name',
'Add': '/create',
'Update': '/update/pk',
'Delete': '/item/pk/delete'
}
return Response(api_urls)
In the above code, the api_view decorator takes a list of HTTP methods that a views should
response to.
Now let's update our api/[Link] file -
from [Link] import path
from . import views
urlpatterns = [
path('', [Link], name='home')
]
Now let's run our server. Run the
following commands -
python [Link] makemigrations

python [Link] migrate

python [Link] runserver


Now head to [Link]
CRUD Opetration with Django Rest Framework
Django Rest Framework - Create View :-Now ourk create view will use the POST
method for inserting data into our database. Let's create our add_items function in the
[Link] file.
from rest_framework import serializers
from rest_framework import status
@api_view(['POST'])
def add_items(request):
item = ItemSerializer(data=[Link])
# validating for already existing data
if [Link](**[Link]).exists():
raise [Link]('This data already exists')
if item.is_valid():
[Link]()
return Response([Link])
else:
return Response(status=status.HTTP_404_NOT_FOUND)
Now let's update our [Link] file and add the endpoint for the create view function we just created.
from [Link] import path
from . import views
urlpatterns = [
path('', [Link], name='home'),
path('create/', views.add_items, name='add-items'),
]
Visit [Link]
Django Rest Framework - Read View

Now our list view will use the GET method for retrieving data from our
database. Let's create our view_items function in the [Link] file. This
view_items function will either show all the data or filtered data queried by
the user according to the category, subcategory, or name.
In [Link]
@api_view(['GET'])
def view_items(request):
# checking for the parameters from the URL
if request.query_params:
items = [Link](**request.query_params.dict())
else:
items = [Link]()
# if there is something in items else raise error
if items:
serializer = ItemSerializer(items, many=True)
return Response([Link])
else:
return Response(status=status.HTTP_404_NOT_FOUND)
In [Link]

from [Link] import path


from . import views
urlpatterns = [
path('', [Link], name='home'),
path('create/', views.add_items, name='add-items'),
path('all/', views.view_items, name='view_items'),
]
Now visit [Link]
Django Rest Framework - Update View
Now for our update view function we will use the POST method. Let's create our update_items
function in the [Link] file. This view function will update a particular item from the database. It will
filter the item with the help of the primary key.
In [Link]
In [Link]
from [Link] import path
@api_view(['POST']) from . import views
def update_items(request, pk):
item = [Link](pk=pk) urlpatterns = [
data = ItemSerializer(instance=item, data=[Link]) path('', [Link], name='home'),
path('create/', views.add_items,
if data.is_valid(): name='add-items'),
[Link]() path('all/', views.view_items,
return Response([Link]) name='view_items'),
else: path('update/<int:pk>/',
return Response(status=status.HTTP_ views.update_items, name='update-items'),
404_NOT_FOUND)
]
Django Rest Framework - Delete View
For our delete view function we will use the DELETE method. Let's create our delete_items
function in the [Link] file. This view function will delete a particular item from the database.
In [Link] In [Link]
from [Link] import path
@api_view(['DELETE']) from . import views
def delete_items(request, pk):
item = get_object_or_404(Item, pk=pk) urlpatterns = [
[Link]() path('', [Link],
return Response(status=status.HTTP_202_ name='home'),
ACCEPTED) path('create/', views.add_items,
name='add-items'),
path('all/', views.view_items,
name='view_items'),
path('update/<int:pk>/',
views.update_items,
name='update-items'),
path('item/<int:pk>/delete/',
views.delete_items, name='delete-items'),
Now visit [Link] See the below GIF for better understanding.
URL Routing in DRF?
In any Django or DRF application, URL routing is the process of mapping a URL path to a view — i.e., deciding what code runs
when a specific URL is accessed by a user or client. In Django Rest Framework (DRF), routing determines how HTTP requests
(like GET, POST, PUT, DELETE) are connected to your API views.

Two Main Approaches to URL Routing in DRF


Manual URL mapping (using path() or re_path() manually in [Link])
Automatic routing (using Routers — e.g. DefaultRouter, SimpleRouter)

Manual URL Mapping


You can define each endpoint manually using Django’s path() or re_path() functions.

Example
Let’s say you have a [Link] file like this:

# [Link]
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(['GET'])
def hello_world(request):
return Response({"message": "Hello, World!"})
Now, map this view to a URL in [Link]:

# [Link]
from [Link] import path
from . import views
urlpatterns = [
path('hello/', views.hello_world, name='hello_world'),
]
When you visit [Link] you’ll get:

{"message": "Hello, World!"}

This approach works well for small APIs but becomes cumbersome as your project grows.
Automatic URL Routing with Routers
DRF provides routers to automatically generate URL routes for your
ViewSets. Step 2: Create a Serializer
# [Link]
Step 1: Create a Model from rest_framework import serializers
from .models import Student
# [Link]
from [Link] import models class StudentSerializer([Link]):
class Meta:
class Student([Link]): model = Student
fields = '__all__'
name = [Link](max_length=100)
age = [Link]() Step 3: Create a ViewSet
grade = [Link](max_length=10) # [Link]
from rest_framework import viewsets
def __str__(self): from .models import Student
return [Link] from .serializers import StudentSerializer

class StudentViewSet([Link]):
queryset = [Link]()
serializer_class = StudentSerializer
# [Link] What the Router Does Automatically

The DefaultRouter automatically creates all the standard


from [Link] import path, include
CRUD URLs for you.
from rest_framework.routers import
DefaultRouter HTTP URL Action Description
from .views import StudentViewSet Method

/students/
router = DefaultRouter() GET list Get all students

[Link](r'students', StudentViewSet) POST /students/ create Add a new student

urlpatterns = [ GET /students/{id}/ retrieve Get one student


path('', include([Link])),
PUT /students/{id}/ update Update a student
]
PATCH /students/{id}/ partial_upda Update partially
te

DELETE /students/{id}/ destroy Delete a student


Types of Routers

Router Description

SimpleRouter Creates routes but no default


root API endpoint
DefaultRouter Includes a default root API view at /
(useful for browsing APIs)

CustomRouter You can extend the router class


to define custom URL patterns
What Is Postman?
Postman is an API development and testing tool .

Postman is a comprehensive API testing tool that simplifies creating, testing, and documenting APIs.

It provides an intuitive user interface that enables developers to design and test APIs and automate their
testing processes easily.

Postman also supports collaboration among team members by allowing them to share and version control
their API tests and collections.

● Send HTTP requests (GET, POST, PUT, DELETE, PATCH, etc.)

● Inspect responses (status codes, headers, data)

● Test APIs manually and automatically

● Organize and share API requests


● Simulate authentication, environment variables, and more.

It’s a GUI tool that replaces using curl or command-line tools for API testing.
Why Use Postman for API Testing?
API testing is crucial for ensuring reliability and preserving consumer trust. Its early issue detection
and automation conserve resources, allowing teams to focus on innovation. Integration with CI/CD
pipelines enables rapid iteration and frequent releases with reduced bug risks.
Step 1. Sign up for a Postman Account
The first step is to create an account on Postman. You can create an account by downloading Postman on
Windows/MacOS or using the Postman online.
Step 2. Create a New Request
Once you have installed Postman, you can create a new request by clicking the "New" button in
the top left corner of the Postman window. Select " HTTP Request" to create a new request.
Step 3. Enter Request Methods, Parameters
Next, you need to enter the details of the API request you want to test. It includes the URL, HTTP
methods, and any parameters or headers the API requires. You can also add a request body if
required. Creating a GET request for Postman API testing as an example.
Step 4. Send the Request
Once you have entered the request details, click the "Send" button in Postman to send the

request to test the API. Postman will display the response in the interface, including the

response status, headers, and body.


Step 5. Create a Postman Collection
One of the key features of Postman is the Collection Runner, which allows developers to execute
multiple requests in a single run. With the Collection Runner, you can specify Postman variables,
set up test suites, and generate reports to track the results of your API testing.

If you want to test multiple API requests, you can create a collection to group them. To create a
collection, click the "New" button and select "Collection". Give the collection a name and
description to help you remember.
Step 6. Add Requests to the Collection
Once you have created a collection, you can add requests by clicking the "Add Request" button. Enter the request details as before,
and click the "Save" button to save the request to the collection.
Step 7. Use the Postman Collection Runner
Postman's Collection Runner feature allows you to simultaneously run multiple requests in a collection. To use the Collection
Runner, click on the "Runner" button in the top right corner of the Postman window. Select the collection you want to run, and click
the "Start Run" button.
Step 8. Analyze the Test Results
Once the Collection Runner has finished running the requests, Postman will display the test results in the interface. You can see
which requests passed and failed and view detailed information about each request.
Benefits of Using Postman
● Easy GUI for testing APIs

● Automates testing and documentation

● Supports all HTTP methods and authentication schemes

● Enables team collaboration

● Great for both manual and automated API testing


Microservices Design and Inter-service
Communication:
Why Decompose an Application?
In traditional monolithic architectures, the entire application (UI, business logic,
data access) is built as one unit.
This causes problems as the system grows:

● Harder to maintain
● Slower deployments
● Scaling is inefficient (must scale the whole system)
● One bug can affect the entire application

Principles of Decomposition
When breaking a monolithic application into microservices, the goal is to identify
bounded contexts logical parts of the system that can function independently.
Example: From Monolith → Microservices
Monolithic App:
/ecommerce
/users
/products
/orders
/payments
/shipping
All modules share one codebase and database.
After Decomposition:

Microservice Responsibility Example Endpoint

User Service Manage users & /api/users/


authentication
Product Service Handle product data /api/products/

Order Service Manage orders /api/orders/

Payment Service Process payments /api/payments/

Shipping Service Handle shipping info /api/shipping/

Each has:
● Its own database
● Its own API
● Runs on its own container or server
Benefits of Decomposition

Benefit Explanation

Scalability Scale each service independently.

Resilience Failure in one service doesn’t crash the


whole system.

Faster Development Teams work on separate services


concurrently.

Technology Freedom Each service can use the best tech stack.

Easier Deployment Deploy updates independently.


What Is “Database per Service”?
In a microservices architecture, each microservice manages its own [Link] means every service
has its own dedicated database it does not share the same database with other [Link]
concept is called Database per Service.

REST-based Communication Between Microservices


REST (Representational State Transfer) is a lightweight architectural style for designing networked
APIs.
When we say REST-based communication between microservices, it means that microservices
interact with each other over HTTP using RESTful APIs.
Each service exposes REST endpoints that other services can call to get or update data.
eg: - GET [Link]
How REST Communication Works
1. One service exposes an API
○ Example: User Service exposes /api/users/{id}/.

2. Another service consumes that API


○ Example: Order Service calls the User Service’s endpoint to get user info.

3. They communicate via HTTP requests and responses


○ Using JSON as the standard data format.
Example: REST Communication Flow

Scenario:
The Order Service needs user data from the User Service.

User Service exposes an endpoint:


# user_service/[Link] (Django REST Framework)
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(['GET'])
def get_user(request, user_id):
user = {"id": user_id, "name": "Alice", "email": "alice@[Link]"}
return Response(user)
API Endpoint:
GET [Link]
Order Service consumes this endpoint:
# order_service/[Link]
import requests
def get_user_data(user_id):
url = f"[Link]
response = [Link](url)
if response.status_code == 200:
return [Link]()
else:
return None
Order Service uses that data in its workflow:
# order_service/[Link]
@api_view(['POST'])
def create_order(request):
user_id = [Link]("user_id")
user_data = get_user_data(user_id)
if not user_data:
return Response({"error": "User not found"}, status=404)
# Proceed to create order
order = {"order_id": 1, "user": user_data, "status": "Created"}
return Response(order)
Now, both services are independent but communicate seamlessly through
REST.
Typical REST (Representational State Transfer)Communication Patterns
1. Request–Response (Synchronous)
● One service directly calls another’s endpoint.
● Immediate response expected.

How It Works
1. Service A sends an HTTP request to Service B
2. Service A waits (blocks) until Service B returns a response
3. Service A continues processing based on that response

Example
● Order Service → GET /users/1/
Order Service retrieves user information directly from User Service.

Use Cases

● Fetching data (user info, product listings, availability checks)


● Operations requiring immediate confirmation
e.g., reserve inventory, validate coupon, calculate shipping
2. Asynchronous REST (Callback/Webhook)
Service A sends a request to Service B but does NOT wait for the final result.
Instead, Service B later calls back Service A when processing is complete.
How It Works
1. Service A sends initial request (e.g., start payment)
2. Service B acknowledges the request (202 Accepted or 200 OK)
3. Service B processes the work in the background
4. When finished, Service B sends a callback to Service A

Example:- Payment Service → POST /callback/payment-status/

Example Flow

●Order Service → "Start Payment"


●Payment Service → returns: Accepted, processing…
●Payment Service → later sends: Payment Success/Failure to callback URL

Use Cases
● Long-running operations ● Integrating external systems
○ Payment processing
○ Stripe, PayPal, GitHub Webhooks
○ Report generation
○ Machine learning jobs
○ File conversions
Basic Error Handling between Services
In a microservices architecture, multiple services depend on each other through network
calls (e.g., REST APIs).
If one service fails, times out, or returns invalid data, it can cause cascading failures unless
properly handled.
So, Error Handling between services is about:
● Detecting errors during inter-service communication
● Responding gracefully
● Preventing system-wide crashes
● Informing other services or users meaningfully

Why Is Error Handling Important in Microservices?


● Microservices are distributed so failures are inevitable.
● Good error handling keeps the system resilient and fault-tolerant.
How Error Handling Works (Step-by-Step)
Example Scenario
● Order Service calls Payment Service to process a payment.
● If Payment Service fails, the Order Service must handle it gracefully.
Step 1: Call Another Service
import requests
def process_payment(order_id, amount):
url = f"[Link]
payload = {"order_id": order_id, "amount": amount}
try:
response = [Link](url, json=payload, timeout=3)
response.raise_for_status() # Raises HTTPError if not 200–299(Success)
return [Link]()
except [Link]:
return {"error": "Payment service timed out"}
except [Link]:
return {"error": "Payment service not reachable"}
except [Link] as e:
return {"error": f"Payment service error: {[Link].status_code}"
Step 2: Handle Errors Gracefully
When calling this from the Order Service:

def create_order(order_data):
payment_result = process_payment(order_data["id"], order_data["total"])
if "error" in payment_result:
# Log and respond meaningfully
return {"status": "failed", "reason": payment_result["error"]}
else:
return {"status": "success", "payment": payment_result}
This way, Order Service doesn’t crash it logs the issue and handles it
gracefully.
Error Handling key concept :-
Microservices communicate over a network → network is unreliable → errors must be
expected and handled gracefully.

Types of Errors
1. Client-side errors (400–499)
A. Wrong input, missing data

2. Server errors (500–599)

A. Internal exceptions
B. Database offline
C. Dependency service failure

[Link]/Network errors

A. Timeouts
B. Connection resets
C. Service unreachable
Handling Errors
1. Timeouts

● Never wait forever for another service.


● Example: If Payment Service takes more than 5 seconds → stop waiting.
● Eg:- Example (Python / DRF + requests):

import requests

def call_payment_service():

try:

response = [Link]("[Link] timeout=5)

return [Link]()

except [Link]:

return {"error": "Payment Service timeout after 5 seconds"}


2. Retries with Limits

● Retry only a few times, with a delay.


● Newman warns against retry storms → use exponential backoff.

Example
import requests, time
def fetch_data():
retries = 3
delay = 1 # start with 1 second
for attempt in range(retries):
try:
return [Link]("[Link]
except [Link]:
[Link](delay)
delay *= 2 # exponential backoff (1s → 2s → 4s)

return {"error": "Inventory Service unreachable after 3 retries"}


3. Circuit Breaker Pattern

● If a service keeps failing → open circuit → stop calling temporarily.

Example (Simple Manual Circuit Breaker)


import time
FAIL_COUNT = 0
CIRCUIT_OPEN = False
OPEN_UNTIL = 0
def call_shipping_service():
global FAIL_COUNT, CIRCUIT_OPEN, OPEN_UNTIL

# If circuit is open, return immediately


if CIRCUIT_OPEN and [Link]() < OPEN_UNTIL:
return {"error": "Circuit open: Shipping Service temporarily disabled"}
try:
response = [Link]("[Link]
FAIL_COUNT = 0 # success → reset failures
return [Link]()
except:
FAIL_COUNT += 1
if FAIL_COUNT >= 3:
CIRCUIT_OPEN = True
OPEN_UNTIL = [Link]() + 10 # open for 10 seconds
return {"error": "Shipping Service failed"}
4. Fallback Responses
● If user profile service is down → return cached/user-basic info.

Example
import requests
CACHED_USER = {
"id": 1,
"name": "Guest User",
"email": "guest@[Link]"
}
def get_user_profile():
try:
return [Link]("[Link]
except:
return {"warning": "User Service down", "data": CACHED_USER}
5. Consistent Error Formats

● When designing APIs or services, all errors should follow a consistent structure so that
clients can handle them reliably.

Example of standardized error response:


{
"status": "error",
"code": "SERVICE_UNAVAILABLE",
"message": "Payment Service is temporarily unavailable",
"timestamp": "2025-11-30T10:45:23Z"
}

Using it in DRF:
def error_response(message, code="BAD_REQUEST"):
return {
"status": "error",
"code": code,
"message": message,
"timestamp": [Link]().isoformat()
}
Service Discovery
Service discovery is a mechanism used in microservices and distributed systems that allows services to
automatically find and communicate with each other without needing hard-coded IP addresses or URLs.

Why Service Discovery?

In microservices, each service often runs on:

● Different servers
● Dynamic IPs
● Containers (Docker, Kubernetes)
These services start, stop, and scale automatically. So you cannot hard-code their
[Link] discovery solves this.
Two Types of Service Discovery
1. Client-Side Discovery

● Client queries the service registry


● Client chooses one instance and communicates.

Client → Service Registry → Instance of Order Service

1. What is Client-Side Discovery?


In client-side discovery, the client itself does the discovery work.

Steps
1. Client asks Service Registry:
“Give me all running instances of Order Service.”
2. Service Registry returns:

○ Order Service at IP: [Link]:8001

○ Order Service at IP: [Link]:8001

○ (multiple copies for load balancing)


3. Client chooses one instance (example: based on round-robin).
4. Client directly sends the request to that chosen instance.
Example
Imagine a Shopping App (Client) wants to place an order.
Services Involved
● Client App
● Service Registry (e.g., Netflix Eureka / Consul / etc.)
● Order Service (multiple copies running)
⭐ Example Steps
Step 1: Client → Service Registry
The shopping app asks:
“Where is Order Service running?”
Step 2: Service Registry Response
Service Registry replies with list of all Order Services:
Order-Service-1 → [Link]:8001
Order-Service-2 → [Link]:8001
Order-Service-3 → [Link]:8001
Step 3: Client Chooses One Instance
Client uses load balancing techniques like:
● Round Robin
● Random
● Least Connections

Example: It chooses Order-Service-2 ([Link]:8001)


Step 4: Client → Order Service
Client directly sends API call:
POST [Link]
Body: {"product_id": 55, "qty": 2}

Order Service processes the order and sends back:


Response: {"status": "Order Placed Successfully"}
2. Server-Side Discovery
● Client sends request to a load balancer or API Gateway.
● Load balancer queries registry and forwards traffic.
Client → Load Balancer → Service Registry → Service Instance

How It Works (Step-by-Step)


1. Client → Load Balancer / API Gateway
The client sends the request directly to:
● Load Balancer (e.g., NGINX, AWS ELB, Kubernetes Service)
or

● API Gateway (e.g., Kong, Zuul, Nginx, AWS API Gateway)

2. Load Balancer → Service Registry


The load balancer asks the service registry:
“Give me available instances of Order Service.”
3. Service Registry → Load Balancer
Registry returns multiple instances:

● Order Service 1 → [Link]:8001

● Order Service 2 → [Link]:8001

4. Load Balancer Chooses One Instance


Load balancer applies load balancing (round robin, least load).
Selects one instance.

5. Load Balancer → Service Instance


Request is forwarded to the chosen instance.
Client doesn’t know where the service is running.
Real-Life Example
Step 5: Load balancer →
Step 1: Client → Load Balancer / API Gateway Order Service
Client calls: The request is forwarded:
POST [Link]
POST
Step 2: Load Balancer → Service Registry [Link]
orders
Load balancer (e.g., NGINX/Kubernetes) queries service registry:
“Where is Order Service running?”
Order is processed → Response
returned to client.
Step 3: Service Registry returns instances
[Link]:8001
[Link]:8001
[Link]:8001

Step 4: Load balancer picks one instance


Example: Picks [Link]:8001
Simple Example
Imagine a microservice system:
● Order Service
● Payment Service
● User Service

Payment service wants to call Order service.


Without service discovery:
[Link]
If IP changes → everything breaks.
With service discovery:
[Link]
Registry automatically maps this to the correct IP.
Real life Example (Netflix Eureka)
1. Order Service registers itself → Eureka
When Order Service starts, it sends a registration request to Eureka:

Order Service → Eureka Server:

"Hello, I am Order-Service. My address is [Link]

Eureka saves this information in its registry.

Order Service [Link] (Spring Boot example)


spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: [Link]
register-with-eureka: true
fetch-registry: true

✔ Order Service is now stored in Eureka’s list.


2 Payment Service asks Eureka:
“Where is Order Service running?”

3 Eureka returns IP + port

4. Payment Service sends the request


Basic API Gateway Concept
An API Gateway is a single entry point that stands between clients (mobile apps, web apps, external systems) and your
internal microservices. Instead of allowing clients to directly call each microservice, all requests first pass through the API
Gateway.

Functions of API Gateway

Request Routing
● Directs incoming client requests to the appropriate microservice

● Routes based on URL path, HTTP method, headers, or hostnames

● Hides internal service locations from clients


Authentication & Authorization
Authentication
Validate JWT Token

● Check signature
● Check expiration (exp)
● Check issued-at (iat)
● Check not-before (nbf)
● Check issuer (iss)
● Check audience (aud)
● Check scopes / roles
Check token type (access / refresh)
● Check token revocation (optional)
● Extract user identity (sub / user_id)

Validate API Key

● Check API key exists


● Check API key status (active / disabled)
● Check expiration / rotation
● Check rate limits
● Check permissions / access level
● Check IP restrictions (optional)
Authorization
Role-Based Access Control (RBAC)

● Check user roles


● Match roles with allowed endpoints
● Apply service-level role policies

Scope-Based Authorization (OAuth2)

● Check scopes in JWT (e.g., read:users, write:orders)


● Ensure scopes match resource access

Attribute-Based Access Control (ABAC)

● Validate resource ownership


● Validate user attributes (department, tenant, region)
● Validate context (time, device, location)

Permission Mapping

● Map roles → permissions


● Validate permissions for each microservice route
Rate Limiting & Throttling
● Controls how many requests a client can send in a given time

● Prevents abuse, brute-force attacks, and overuse

● Helps maintain system stability during traffic spikes

Load Balancing
● Distributes incoming traffic across multiple service instances

● Improves availability and performance

● Ensures no single service instance is overloaded


Protocol Translation
● Converts between different communication types:

○ REST ↔ gRPC

○ HTTP ↔ WebSockets

○ HTTP ↔ TCP

● Allows microservices to use different protocols internally


Response Aggregation
● Combines results from multiple microservices into a single response

● Reduces the number of calls the client has to make

● Improves performance and reduces latency

Security Filtering
● Applies IP whitelisting/blacklisting

● Performs CORS policy enforcement

● Protects against common threats (e.g., injection attacks)


Logging & Monitoring
● Logs all incoming requests
● Tracks metrics such as latency, error rates, and traffic volume
● Supports distributed tracing (e.g., Jaeger, Zipkin)

Error Handling

● Provides consistent error responses


● Manages retries, fallbacks, circuit breakers
● Protects clients from internal service failures

Request & Response Transformation


● Modifies headers, query parameters, or body content
● Converts formats (JSON ↔ XML, etc.)
● Normalizes data before sending to clients
Basic Logging and Error Handling:
Basic Logging in Microservices
Basic Logging and Error Handling are fundamental parts of microservices and API
development.
They help developers understand what happened inside the service and how to respond when
something goes wrong.

1. Basic Logging

Logging means recording important events that happen inside an application.


These events help with debugging, monitoring, performance analysis, and auditing.
● Why Logging Is Important
1. Helps find the root cause of failures
2. Supports system monitoring
3. Helps understand service behavior in distributed systems
4. Enables tracking user activities and request flows
5. Useful for auditing, security, and compliance
What to Log
According to microservice best practices:

1. Request logs

○ Incoming requests, URL, user identity (if available)

2. Response logs

○ Status code, time taken

3. Error logs

○ Exceptions, stack traces, error messages

4. Business events

○ Example: “Order created”, “Payment processed”

5. Service communication logs

○ Outgoing API calls to other services


Structured Logging in Django
Structured logging means producing logs in machine-readable formats (mostly JSON) so they can
be sent to monitoring tools.

What is Structured Logging?


Instead of printing simple text like:

Error occurred!

We use structured, machine-readable logs like JSON:

"time": "2025-01-01 10:30:00",

"level": "ERROR",

"service": "order-service",

"message": "Payment failed"

}
Why Structured Logging? Django Structured Logging Example
It helps tools like: Django allows structured logging using LOGGING settings.
● Kibana LOGGING = {
● Elasticsearch "version": 1,
● Jaeger
"handlers": {
● Zipkin
to search and visualize logs easily. "console": {
"class": "[Link]",
"formatter": "json",
},
},
"formatters": {
"json": {
"format": '{"time": "%(asctime)s", "level":
"%(levelname)s","msg": "%(message)s"}'
}
},
"root": {
"handlers": ["console"],
"level": "INFO"
}
}
Basic Security in Microservices
Security has two main parts:

A. Authentication (Who are you?)


Common methods in microservices:
1. JWT Token (Most Popular)
User logs in → gets a token → sends token in every request.

2. API Keys
Good for service-to-service communication.

3. OAuth2
Used by big apps like Google Login, Facebook Login.

4. mTLS (mutual TLS)


Both services verify each other.
B. Authorization (What are you allowed to do?)
Types:
● RBAC (Role Based Access Control)
Example: Admin / User / Manager

● Permission-based control
Example: user.can_add_product = True

Django REST Framework Permissions:


permission_classes = [IsAuthenticated]
C. Service-to-Service Security
Newman stresses zero-trust principle.s:

● services do not trust incoming requests by default

● use secure communication (mTLS or shared secrets)


4. Error Handling & Circuit Breaker Pattern
Based on ideas from:
● Sam Newman (reliability patterns, timeouts, retries)
● Chris Richardson (fault tolerance patterns, especially circuit breaker)
● Ziade (error handling in Python microservices)

A. Error Handling in Microservices


Microservices rely on network communication, so failures are expected.

Typical Error Types


● Timeouts
● Network failures
● Service unavailable
Validation errors
● Dependency failures

Newman and Ziade suggest using:


● Retry strategies
● Exponential backoff
● Graceful degradation
● Consistent error responses (e.g., JSON error bodies)
B. Circuit Breaker Pattern (Introduction)
Richardson provides the most complete explanation of this pattern.

If a remote service begins failing repeatedly, the circuit breaker “opens,” and the calling service stops
sending requests for a short time.

States
1. Closed – everything works normally.
2. Open – service is considered down; calls are blocked or fallback is used.
3. Half-Open – test if the service has recovered.

Why It's Important


It prevents:

● cascading failures
● long timeouts
● system-wide slowdowns

Tools like Resilience4j, Envoy, or service meshes implement it.

You might also like