DEV Community

Deepika Pusala
Deepika Pusala

Posted on

Instagram Clone Backend — Part 2: Frameworks and Servers (FastAPI, Uvicorn, ASGI & Starlette)

When designing a photo and video sharing platform like Instagram, your backend needs to serve thousands of requests per second: uploading posts, querying feeds, checking follower status, and verifying JWT sessions.

To achieve this level of performance without complex multi-threading bugs, modern Python relies on a specialized server stack: FastAPI, Starlette, ASGI, and Uvicorn.

In this tutorial, we will demystify how these four technologies fit together like a set of building blocks, and how they power our Instagram clone backend.


1. The Big Picture: How They Fit Together

A common point of confusion for developers is telling these four technologies apart. Here is the architectural hierarchy:

+-----------------------------------------------------------+
|                          CLIENT                           |
|           (React Web App, Mobile App, Postman)            |
+-----------------------------+-----------------------------+
                              | HTTP / WebSocket Request
                              v
+-----------------------------------------------------------+
|                  SERVER RUNTIME: Uvicorn                  |
|          (ASGI Web Server / Network Listener)             |
+-----------------------------+-----------------------------+
                              | ASGI Protocol (scope, receive, send)
                              v
+-----------------------------------------------------------+
|            CORE WEB TOOLKIT: Starlette (ASGI App)         |
|      (Routing, Middleware, Exception Handling, Cookies)   |
+-----------------------------+-----------------------------+
                              | Extends & Enhances
                              v
+-----------------------------------------------------------+
|               HIGH-LEVEL FRAMEWORK: FastAPI               |
|      (Pydantic Validation, Dependency Injection, Docs)    |
+-----------------------------------------------------------+
Enter fullscreen mode Exit fullscreen mode

Think of it like a restaurant:

  • ASGI: The communication standard (the universal language the kitchen and waiters speak).
  • Uvicorn: The fast delivery runner bringing raw orders from customers into the kitchen.
  • Starlette: The prep station handling essential tools (plates, sauces, tickets).
  • FastAPI: The master chef crafting gourmet recipes, verifying ingredients, and printing menus.

2. What is ASGI? (Asynchronous Server Gateway Interface)

Before ASGI, the Python standard was WSGI (Web Server Gateway Interface), used by frameworks like Flask and Django.

  • WSGI is synchronous: A request enters, the server process/thread handles it from start to finish, blocking until done. It cannot natively handle WebSockets or async long-polling.
  • ASGI is asynchronous: It is a standard specification designed to allow multiple asynchronous Python web frameworks to talk to asynchronous web servers.

An ASGI application is simply an async function with three parameters:

async def simple_asgi_app(scope, receive, send):
    """A minimal ASGI application."""
    if scope["type"] == "http":
        await send({
            "type": "http.response.start",
            "status": 200,
            "headers": [[b"content-type", b"text/plain"]],
        })
        await send({
            "type": "http.response.body",
            "body": b"Welcome to Instagram Clone API!",
        })
Enter fullscreen mode Exit fullscreen mode

While writing raw ASGI apps is possible, handling routing, cookies, headers, and file uploads manually would be tedious. That is where Starlette comes in.


3. Starlette: The Lightweight ASGI Engine

Starlette is a lightweight, high-performance ASGI framework/toolkit. It provides all the core web machinery:

  • High-performance URL routing.
  • Custom middleware support (CORS, security headers, request ID tracking).
  • Session, cookie, and static file management.
  • Native WebSocket support for real-time notifications and direct messages.

FastAPI is actually built directly on top of Starlette! Every FastAPI app is a subclassed, feature-rich Starlette application:

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

async def homepage(request):
    return JSONResponse({"status": "Instagram API alive"})

app = Starlette(routes=[Route("/", homepage)])
Enter fullscreen mode Exit fullscreen mode

4. FastAPI: The Modern Developer Superpower

If Starlette handles raw web plumbing, FastAPI adds the developer magic:

1. Automatic Request Validation (via Pydantic)

FastAPI validates request bodies, headers, and query parameters before your business logic even runs. If a client sends invalid data, FastAPI automatically replies with a detailed 422 Unprocessable Entity error:

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI(title="Instagram Clone API")

class CreatePostSchema(BaseModel):
    caption: str = Field(..., max_length=2200)
    image_url: str

@app.post("/posts")
async def create_post(post_data: CreatePostSchema):
    # post_data is guaranteed to be valid and type-safe!
    return {
        "message": "Post created successfully",
        "caption": post_data.caption
    }
Enter fullscreen mode Exit fullscreen mode

2. Powerful Dependency Injection System (Depends)

FastAPI has an elegant dependency injection engine. In our Instagram backend, we use it for database sessions and authentication:

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    # Decodes and validates JWT token
    user = verify_token_and_fetch_user(token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired token"
        )
    return user

@app.get("/users/me/feed")
async def get_my_feed(current_user = Depends(get_current_user)):
    # Only authenticated users reach this code
    return {"feed_owner": current_user.username, "posts": []}
Enter fullscreen mode Exit fullscreen mode

3. Interactive API Documentation Out-of-the-Box

FastAPI inspects your code and auto-generates interactive OpenAPI documentation:

  • Swagger UI at /docs (allows testing endpoints directly in the browser).
  • ReDoc at /redoc (clean, readable API specification).

5. Uvicorn: The High-Speed ASGI Web Server

FastAPI and Starlette define what happens when a request arrives, but they cannot listen on network ports by themselves. That is Uvicorn's job.

Uvicorn is a lightning-fast ASGI server implementation using:

  • uvloop: An ultra-fast drop-in replacement for the default Python event loop, written in C and built on libuv (the same event loop powering Node.js).
  • httptools: A fast Python binding for the NodeJS HTTP parser.

Running the Server in Development vs. Production

In development, we run Uvicorn with auto-reload:

uvicorn main:app --reload --host 0.0.0.0 --port 8000
Enter fullscreen mode Exit fullscreen mode
  • main: Refers to main.py.
  • app: Refers to the app = FastAPI() object defined inside main.py.
  • --reload: Automatically reloads the server whenever code changes are detected.

In a production environment, you typically run multiple Uvicorn worker processes managed by a process manager:

uvicorn main:app --workers 4 --host 0.0.0.0 --port 8000
Enter fullscreen mode Exit fullscreen mode

6. How It All Connects in Our Instagram Project

Here is a look at how this stack comes together in our real backend:

  1. Incoming Request: A client sends a GET /feed request containing a Bearer token.
  2. Uvicorn: Accepts the TCP connection, parses HTTP bytes using httptools, and constructs the ASGI scope.
  3. Starlette: Runs custom middleware (e.g., logging response times, setting CORS headers for our React frontend).
  4. FastAPI:
    • Matches the route /feed.
    • Runs Depends(get_current_user) to authenticate the session.
    • Executes the asynchronous database query (await db.execute(...)).
    • Serializes the output using Pydantic schemas.
  5. Response: Uvicorn sends the formatted JSON back across the wire to the user.

Key Takeaways

Technology Role What It Does In Our Project
ASGI Specification Standardizes async communication between Python servers and apps.
Uvicorn Web Server Listens on ports, parses raw network packets, runs the event loop.
Starlette Core Toolkit Provides routing, middleware, cookies, and low-level HTTP primitives.
FastAPI Web Framework Provides input validation, JWT dependencies, OpenAPI docs, and clean endpoints.

In the next post, we will look at Database Integration & Migrations: PostgreSQL, SQLAlchemy (Asyncio), and Alembic!

Top comments (0)