> ## Documentation Index
> Fetch the complete documentation index at: https://blog.mubeen.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Anatomy of a clean backend

# The Anatomy of a Clean Backend: From Spaghetti to Architecture

When you first start building an API with FastAPI (or any framework), the goal is simple: **Make it work.**

But as your application grows from a weekend project into a serious SaaS platform, the "simple" way becomes a nightmare. Let's trace the evolution of a feature. Say, **"Registering a User"** to understand why we end up with the **Controller → Service → Repository** pattern.

### Phase 1: The "Do It All" Controller (The Junior Phase)

In the beginning, you put everything in one place. The Controller (the API route) handles the HTTP request, validates the email, calculates the password hash, connects to the database, and executes SQL.

**The Code:**

```python theme={null}
#  THE PROBLEM: Everything is mixed together
@app.post("/register")
async def register(user_data: UserSchema):
    # 1. Logic mixed with HTTP
    if "@" not in user_data.email:
        raise HTTPException(status_code=400, detail="Bad email")
    
    # 2. Database connection management inside the route
    async with db.connect() as conn:
        # 3. Raw SQL mixed with logic
        await conn.execute("INSERT INTO users ...")
        
    return {"status": "created"}
```

**Why this fails:**

1. **It's Un-testable:** You can't test the email validation logic without spinning up a real database.
2. **No Reuse:** If you want to create a user from a CLI command or a background script, you have to copy-paste this code.
3. **Connection Chaos:** If you call another function that *also* opens a connection, you now have two open connections for one request.

### Phase 2: The Separation of Duties (The Intermediate Phase)

You realize the Controller is doing too much. You decide to split the code into three layers.

1. **Controller:** "I only handle HTTP (JSON in, JSON out)."
2. **Service:** "I only handle Logic (Rules, calculations, decisions)."
3. **Repository:** "I only handle Data (SQL, Database)."

**The Analogy: The Restaurant**

* **Controller = The Waiter.** They take the order (Request) and bring food (Response). They don't cook.
* **Service = The Chef.** They take ingredients and cook the meal. They don't serve tables.
* **Repository = The Supplier.** They provide the raw ingredients (Data). They don't cook.

**The New Problem: How do they talk?**
Now that you have separated them, you have to connect them. The naive way is to let the Service build the Repository.

```python theme={null}
#  THE TRAP: Hard Dependency
class UserService:
    def __init__(self):
        # The Service creates its own Supplier (Repository)
        # It creates its own DB connection
        self.repo = UserRepository(db_url="postgres://...") 
```

**Why this still fails:**

* **The "Mocking" Problem:** If you want to test the Chef (Service), you are forced to bring in the real Supplier (Repository). You can't just say, "Pretend we have ingredients." The Service is hard-coded to talk to the real database.

### Phase 3: Dependency Injection (The "Pro" Phase)

This is where we arrive at your solution.

Instead of the Service *creating* the Repository, we **give (inject)** the Repository to the Service.

**The Concept:**
The Chef (Service) says: *"I don't care where the ingredients come from. Just hand me a valid Supplier (Repository) when I start my shift."*

This is **Dependency Injection (DI)**.

We need a "Manager" (FastAPI/`dependencies.py`) to set everything up before the shift starts (before the Request is handled).

**Step 1: The Repository (The Supplier)**
It needs a database connection to work. It doesn't open it; it asks for it.

```python theme={null}
class UserRepository:
    def __init__(self, connection):
        self.conn = connection # Just stores it
```

**Step 2: The Service (The Chef)**
It needs a Repository to work. It asks for it.

```python theme={null}
class UserService:
    def __init__(self, user_repo):
        self.repo = user_repo # Just stores it
```

**Step 3: The Manager (dependencies.py)**
This is the magic glue. It assembles the team.

```python theme={null}
# The Manager builds the chain:
# 1. Get DB -> 2. Build Repo -> 3. Build Service
def get_user_service(db = Depends(get_db)):
    repo = UserRepository(db)
    return UserService(repo)
```

**Step 4: The Controller (The Waiter)**
The Controller just asks for the Service.

```python theme={null}
@app.post("/register")
def register(service = Depends(get_user_service)):
    # The service arrives fully assembled and ready to work!
    service.create_user(...)
```

### Summary: Why did we do all this?

It looks like more code, but here is the payoff:

1. **The "Lego" Effect (Decoupling):**
   Because the Service doesn't create the Repository, you can swap the Repository out.

   * *Today:* You use `PostgresRepository`.
   * *Tomorrow:* You switch to `MongoRepository`.
   * **Result:** You change the wiring in `dependencies.py`, and the Service code **doesn't change at all**.

2. **Testing is a Breeze:**
   When testing the Service, you don't need a database. You can inject a `FakeRepository` that returns dummy data in memory.

   ```python theme={null}
   # Test
   fake_repo = FakeRepo() 
   service = UserService(fake_repo) # Works perfectly!
   ```

3. **Transaction Safety (The "Unit of Work"):**
   Because the DB connection is created at the very top (in `dependencies.py`) and passed down, every repository uses the **exact same connection** for that request.

   * If you save a User and then save a Payment, and the Payment fails, you can rollback **everything** because they share the same session.

### The Final mental model

* **Controller:** The Interface (HTTP).
* **Service:** The Brain (Logic).
* **Repository:** The Storage (SQL).
* **Dependency Injection:** The Assembly Line that puts them together properly so they don't depend on each other hard-codedly.
