Website Backend Development with Python (FastAPI)

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
Website Backend Development with Python (FastAPI)
Medium
from 1 week to 3 months
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Website Backend Development with Python (FastAPI)

FastAPI is a modern Python framework that builds APIs around types. You declare a function with type hints, and FastAPI automatically generates validation through Pydantic, OpenAPI documentation, and JSON Schema. No manual documentation, no separate validators — everything is inferred from types.

FastAPI's performance on asynchronous I/O operations is comparable to Node.js. For CPU-bound tasks — that's a separate question; you need process pools or offloading to Celery.

Basics and Endpoint Structure

from fastapi import FastAPI, Depends, HTTPException, Query, Path, status
from pydantic import BaseModel, EmailStr, Field
from typing import Optional, List
import uvicorn

app = FastAPI(
    title="My API",
    version="1.0.0",
    docs_url="/api/docs",
    redoc_url="/api/redoc"
)

class ProductCreate(BaseModel):
    name: str = Field(..., min_length=2, max_length=255)
    price: float = Field(..., gt=0)
    category_id: int
    description: Optional[str] = None

class ProductResponse(BaseModel):
    id: int
    name: str
    price: float
    category_id: int

    class Config:
        from_attributes = True  # allows creating from ORM objects

@app.get('/api/v1/products', response_model=List[ProductResponse])
async def list_products(
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    category_id: Optional[int] = Query(None),
    db: AsyncSession = Depends(get_db)
):
    offset = (page - 1) * limit
    query = select(Product).offset(offset).limit(limit)
    if category_id:
        query = query.where(Product.category_id == category_id)
    result = await db.execute(query)
    return result.scalars().all()

@app.post('/api/v1/products', response_model=ProductResponse, status_code=status.HTTP_201_CREATED)
async def create_product(
    body: ProductCreate,
    current_user: User = Depends(require_role('admin')),
    db: AsyncSession = Depends(get_db)
):
    product = Product(**body.model_dump())
    db.add(product)
    await db.commit()
    await db.refresh(product)
    return product

Dependency Injection

DI in FastAPI works through Depends — one of the best mechanisms in the Python ecosystem:

from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine

# Database connection per request
async_engine = create_async_engine(settings.DATABASE_URL, pool_size=10)

async def get_db():
    async with AsyncSession(async_engine) as session:
        try:
            yield session
        except Exception:
            await session.rollback()
            raise
        finally:
            await session.close()

# Authentication
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='/api/auth/token')

async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: AsyncSession = Depends(get_db)
) -> User:
    try:
        payload = jwt.decode(token, settings.JWT_SECRET, algorithms=['HS256'])
        user_id: int = payload.get('sub')
    except JWTError:
        raise HTTPException(status_code=401, detail='Invalid token')

    user = await db.get(User, user_id)
    if not user or not user.is_active:
        raise HTTPException(status_code=401, detail='Inactive user')
    return user

def require_role(*roles: str):
    async def checker(user: User = Depends(get_current_user)) -> User:
        if user.role not in roles:
            raise HTTPException(status_code=403, detail='Insufficient permissions')
        return user
    return checker

SQLAlchemy 2.0 (async)

FastAPI works well with SQLAlchemy 2.0 in async mode:

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy import String, Numeric, ForeignKey, DateTime, func

class Base(DeclarativeBase):
    pass

class Product(Base):
    __tablename__ = 'products'

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(255))
    slug: Mapped[str] = mapped_column(String(255), unique=True)
    price: Mapped[float] = mapped_column(Numeric(10, 2))
    category_id: Mapped[int | None] = mapped_column(ForeignKey('categories.id'), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())

    category: Mapped['Category'] = relationship(back_populates='products', lazy='selectin')

lazy='selectin' for relationships — the best choice in async mode, avoids N+1 without explicit joins.

Background Tasks

Simple tasks — through BackgroundTasks, heavy ones — through Celery:

from fastapi import BackgroundTasks
import asyncio

# Light async tasks right in the request
@app.post('/api/orders/{order_id}/confirm')
async def confirm_order(
    order_id: int,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db)
):
    order = await get_order_or_404(order_id, db)
    order.status = 'confirmed'
    await db.commit()

    # Don't wait for completion
    background_tasks.add_task(send_confirmation_email, order.user.email, order_id)
    background_tasks.add_task(update_inventory, order.items)

    return {'status': 'confirmed'}

# Heavy tasks — Celery
from celery import Celery

celery = Celery(__name__, broker=settings.REDIS_URL)

@celery.task(name='generate_report')
def generate_report(user_id: int, date_range: dict):
    # CPU-intensive processing
    pass

Middleware and CORS

from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
import time

app.add_middleware(GZipMiddleware, minimum_size=1000)
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.ALLOWED_ORIGINS,
    allow_credentials=True,
    allow_methods=['*'],
    allow_headers=['*']
)

@app.middleware('http')
async def add_process_time(request: Request, call_next):
    start = time.perf_counter()
    response = await call_next(request)
    duration = time.perf_counter() - start
    response.headers['X-Process-Time'] = str(round(duration * 1000, 2))
    return response

WebSocket

from fastapi import WebSocket, WebSocketDisconnect

class ConnectionManager:
    def __init__(self):
        self.active: dict[int, list[WebSocket]] = {}

    async def connect(self, user_id: int, ws: WebSocket):
        await ws.accept()
        self.active.setdefault(user_id, []).append(ws)

    async def broadcast_to_user(self, user_id: int, message: dict):
        for ws in self.active.get(user_id, []):
            await ws.send_json(message)

manager = ConnectionManager()

@app.websocket('/ws/notifications')
async def notifications_ws(
    websocket: WebSocket,
    token: str = Query(...),
):
    user = await verify_ws_token(token)
    await manager.connect(user.id, websocket)
    try:
        while True:
            await websocket.receive_text()  # keep connection
    except WebSocketDisconnect:
        manager.disconnect(user.id, websocket)

Deployment

FastAPI runs through Uvicorn or Gunicorn with Uvicorn workers:

# Production: multiple workers
gunicorn app.main:app \
  -w 4 \
  -k uvicorn.workers.UvicornWorker \
  --bind 0.0.0.0:8000 \
  --timeout 30 \
  --keepalive 5

Development Timelines

  • Framework + models + auth — 4–7 days
  • API endpoints + validation — 1–2 weeks
  • Integrations and background tasks — 1–2 weeks
  • Tests (pytest + httpx AsyncClient) — 5–7 days

API for a mid-scale website: 4–8 weeks. FastAPI wins when the team knows Python and needs auto-documentation — Swagger/ReDoc is generated from code effortlessly.