Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Managing Database Migrations, Authentication, Middleware, CORS, Background Jobs, and Testing in FastAPI

Tech May 8 4

Database Migrations with Alembic

Install a specific version of Alembic:

pip install alembic==1.13.1

Initialize the Alembic project structure:

alembic init alembic

This creates an alembic.ini file. Update the sqlalchemy.url to match your database configuration:

[alembic]
script_location = alembic
sqlalchemy.url = mysql+pymysql://david:123456@localhost/summary

[loggers]
keys = root

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s

In alembic/env.py, import your SQLAlchemy base model and assign its metadtaa:

from models import Base
target_metadata = Base.metadata

Generate a migration script after defining a new model:

alembic revision --autogenerate -m "create_user_table"

Apply the migration:

alembic upgrade head

For future schema changes, repeat the autogenerate and upgrade steps:

alembic revision --autogenerate -m "add phone field to user"
alembic upgrade head

API Key Authentication

Use APIKeyHeader for simple token-based protection:

from fastapi import FastAPI, Security, HTTPException
from fastapi.security import APIKeyHeader

app = FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")

@app.get("/secure-endpoint")
async def secure_route(api_key: str = Security(api_key_header)):
    if api_key != "secret-token-123":
        raise HTTPException(status_code=401, detail="Unauthorized")
    return {"data": "protected content"}

Middleware Configuration

Add custom middleware to log request processing time and enable CORS:

import time
from fastapi import Request
from fastapi.middleware.cors import CORSMiddleware

@app.middleware("http")
async def add_timing_header(request: Request, call_next):
    start = time.time()
    response = await call_next(request)
    duration = time.time() - start
    response.headers["X-Processing-Time"] = str(duration)
    return response

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Background Task Execution

Schedule lightweight background operations using BackgroundTasks:

from fastapi import APIRouter, BackgroundTasks

router = APIRouter()

def write_log(message: str):
    with open("activity.log", "a") as log:
        log.write(f"{message}\n")

@router.post("/trigger-task")
async def trigger_task(background_tasks: BackgroundTasks):
    background_tasks.add_task(write_log, "User initiated background job")
    return {"status": "accepted"}

Dependency injection can be used to conditionally schedule tasks:

from typing import Optional

def maybe_schedule_task(background_tasks: BackgroundTasks, flag: Optional[str] = None):
    if flag:
        background_tasks.add_task(write_log, f"Flag enabled: {flag}")
    return flag

@router.post("/conditional-task")
async def conditional_task(flag: str = Depends(maybe_schedule_task)):
    if flag:
        return {"result": "logged"}

Note: Avoid injecting dependencies like database sessions directly into background task functions. Pass only serializable data or manage connections inside the task.

Writing Unit Tests

Use TestClient from fastapi.testclient to simulate requests:

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_trigger_background_task():
    response = client.post("/trigger-task")
    assert response.status_code == 200
    assert response.json() == {"status": "accepted"}

def test_conditional_task_without_flag():
    response = client.post("/conditional-task")
    assert response.status_code == 200
    assert response.json() is None

def test_conditional_task_with_flag():
    response = client.post("/conditional-task?flag=test")
    assert response.status_code == 200
    assert response.json() == {"result": "logged"}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.