Ad – 728Γ—90
πŸ“‘ Projects

Python API Project – Quotes REST API

Build a production-ready Quotes REST API using FastAPI and SQLite. Full CRUD, filtering, random endpoint, and Swagger docs in under 100 lines.

⏱️ 20 min read🎯 ProjectsπŸ“… Updated 2026

Setup

Bash
pip install fastapi uvicorn sqlalchemy
uvicorn main:app --reload

Complete Implementation

Python
from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import create_engine, Column, Integer, String, text
from sqlalchemy.orm import DeclarativeBase, Session
import random

engine = create_engine("sqlite:///quotes.db")

class Base(DeclarativeBase): pass

class QuoteModel(Base):
    __tablename__ = "quotes"
    id = Column(Integer, primary_key=True, index=True)
    text = Column(String, nullable=False)
    author = Column(String, nullable=False)
    category = Column(String, default="general")

Base.metadata.create_all(engine)

class QuoteCreate(BaseModel):
    text: str
    author: str
    category: str = "general"

class QuoteResponse(QuoteCreate):
    id: int
    class Config: from_attributes = True

app = FastAPI(title="Quotes API")

@app.get("/quotes", response_model=list[QuoteResponse])
def list_quotes(category: str | None = Query(None), skip: int = 0, limit: int = 20):
    with Session(engine) as db:
        q = db.query(QuoteModel)
        if category: q = q.filter(QuoteModel.category == category)
        return q.offset(skip).limit(limit).all()

@app.get("/quotes/random", response_model=QuoteResponse)
def random_quote(category: str | None = None):
    with Session(engine) as db:
        q = db.query(QuoteModel)
        if category: q = q.filter(QuoteModel.category == category)
        quotes = q.all()
        if not quotes: raise HTTPException(404, "No quotes")
        return random.choice(quotes)

@app.get("/quotes/{quote_id}", response_model=QuoteResponse)
def get_quote(quote_id: int):
    with Session(engine) as db:
        q = db.get(QuoteModel, quote_id)
        if not q: raise HTTPException(404, "Not found")
        return q

@app.post("/quotes", response_model=QuoteResponse, status_code=201)
def create_quote(quote: QuoteCreate):
    with Session(engine) as db:
        q = QuoteModel(**quote.dict())
        db.add(q); db.commit(); db.refresh(q)
        return q

@app.delete("/quotes/{quote_id}", status_code=204)
def delete_quote(quote_id: int):
    with Session(engine) as db:
        q = db.get(QuoteModel, quote_id)
        if not q: raise HTTPException(404, "Not found")
        db.delete(q); db.commit()
Bash
# API docs: http://localhost:8000/docs
Tip: FastAPI auto-generates Swagger at /docs and ReDoc at /redoc β€” use them to test all endpoints without any client code.