Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
**.pyc
*.db
__pycache__/
.env
69 changes: 69 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# FastAPI CRUD App

**Contributor:** AksharGoyal

## Overview
Simple, starter FastAPI application demonstrating CRUD operations backed by SQLAlchemy ORM. Includes a minimal API for creating, listing, updating and deleting "items".

## Tech stack
- Python 3.12+
- FastAPI
- SQLAlchemy
- Uvicorn (ASGI server)
- "uv" as the local environment manager (see pyproject.toml)

## Prerequisites
- Linux
- Python 3.12+
- The `uv` tool is used in these instructions as the environment manager

## Quickstart
1. Create and activate the virtual environment
```sh
curl -LsSf https://astral.sh/uv/install.sh | sh # Install uv
uv venv --python=3.12 # creates .venv by default
source .venv/bin/activate
```

2. Install dependencies
```sh
uv pip install -r requirements.txt
```

3. Run the server
```sh
uv run uvicorn app.main:app --reload
```

## API endpoints
- GET /items/ — List items
- POST /items/ — Create item
- GET /items/{id} — Retrieve single item
- PUT /items/{id} — Update item
- DELETE /items/{id} — Delete item

## Examples
List items:
```sh
curl -X GET http://127.0.0.1:8000/items/
# returns: []
```

Create an item:
```sh
curl -X POST http://127.0.0.1:8000/items/ \
-H "Content-Type: application/json" \
-d '{"title":"A Nice Hoodie","description":"A nice hoodie to wear with style.","price":39.99}'
```

Update item with id 1:
```sh
curl -X PUT http://127.0.0.1:8000/items/1 \
-H "Content-Type: application/json" \
-d '{"title":"A Cool Hoodie","description":"A nice hoodie to wear with style.","price":49.99}'
```

Delete item with id 1:
```sh
curl -X DELETE http://127.0.0.1:8000/items/1
```
Empty file.
73 changes: 73 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/app/controllers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from typing import List, Optional

from sqlalchemy.orm import Session

from . import models, schemas


def get_items(db: Session, skip: int = 0, limit: int = 100) -> List[models.Item]:
"""
Return a list of items from the database.

Args:
db: SQLAlchemy Session
skip: number of records to skip (offset)
limit: maximum number of records to return

Returns:
List of Item instances.
"""
return db.query(models.Item).offset(skip).limit(limit).all()


def get_item(db: Session, item_id: int) -> Optional[models.Item]:
"""
Return a single item by id or None if not found.
"""
return db.query(models.Item).filter(models.Item.id == item_id).first()


def create_item(db: Session, item: schemas.ItemCreate) -> models.Item:
"""
Create and persist a new item.

Commits the transaction and refreshes the instance to populate generated fields (e.g. id).
"""
db_item = models.Item(
title=item.title, description=item.description, price=item.price
)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item


def update_item(db: Session, item_id: int, item: schemas.ItemCreate) -> Optional[models.Item]:
"""
Update fields of an existing item.

Returns the updated item or None if the item does not exist.
"""
db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
if db_item is None:
return None
db_item.title = item.title
db_item.description = item.description
db_item.price = item.price
db.commit()
db.refresh(db_item)
return db_item


def delete_item(db: Session, item_id: int) -> Optional[models.Item]:
"""
Delete an item by id.

Returns the deleted item (detached) or None if not found.
"""
db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
if db_item is None:
return None
db.delete(db_item)
db.commit()
return db_item
20 changes: 20 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/app/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session

"""
Database configuration and session factory.

- Uses a local SQLite database file `items.db` for this example.
- SessionLocal is a SQLAlchemy session factory to be used via dependency injection.
"""

SQLALCHEMY_DATABASE_URL = "sqlite:///./items.db"

engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
# SessionLocal is a factory for sessions. Use `SessionLocal()` to get a Session instance.
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
91 changes: 91 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from typing import Generator

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

from . import controllers, models, schemas
from .database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI(
title="FastAPI CRUD App",
description="Minimal example API demonstrating CRUD operations backed by SQLAlchemy."
)


def get_db() -> Generator[Session, None, None]:
"""
FastAPI dependency that yields a SQLAlchemy Session.

Ensures the session is closed after the request finishes.
Usage: db: Session = Depends(get_db)
"""
db = SessionLocal()
try:
yield db
finally:
db.close()



@app.get("/items/", response_model=list[schemas.Item])
def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
"""
List items with optional pagination.

Query params:
- skip: offset
- limit: maximum number of items to return
"""
items = controllers.get_items(db, skip=skip, limit=limit)
return items


@app.get("/items/{item_id}", response_model=schemas.Item)
def read_item(item_id: int, db: Session = Depends(get_db)):
"""
Retrieve a single item by id.

Returns 404 if the item does not exist.
"""
db_item = controllers.get_item(db, item_id=item_id)
if db_item is None:
raise HTTPException(status_code=404, detail="Item not found")
return db_item


@app.post("/items/", response_model=schemas.Item)
def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db)):
"""
Create a new item.

Body: ItemCreate
"""
return controllers.create_item(db=db, item=item)


@app.put("/items/{item_id}", response_model=schemas.Item)
def update_item(item_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)):
"""
Update an existing item by id.

Returns 404 if the item does not exist.
"""
db_item = controllers.update_item(db, item_id=item_id, item=item)
if db_item is None:
raise HTTPException(status_code=404, detail="Item not found")
return db_item


@app.delete("/items/{item_id}", response_model=schemas.Item)
def delete_item(item_id: int, db: Session = Depends(get_db)):
"""
Delete an item by id.

Returns the deleted item on success; 404 if not found.
"""
db_item = controllers.delete_item(db, item_id=item_id)
if db_item is None:
raise HTTPException(status_code=404, detail="Item not found")
return db_item
21 changes: 21 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from sqlalchemy import Column, Integer, String, Float, Text

from .database import Base


class Item(Base):
"""
SQLAlchemy ORM model for an item.

Columns:
- id: primary key
- title: short title of the item
- description: longer description (Text)
- price: numeric price stored as a float
"""
__tablename__ = "items"

id = Column(Integer, primary_key=True, index=True)
title = Column(String(200), nullable=False, index=True)
description = Column(Text, nullable=True)
price = Column(Float, nullable=False)
26 changes: 26 additions & 0 deletions Domains/Backend/MiniProjects/FastAPI-CRUD-app/app/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from pydantic import BaseModel, Field


class ItemBase(BaseModel):
"""
Shared properties for an item used for input validation.
"""
title: str
description: str | None = None
price: float


class ItemCreate(ItemBase):
"""
Properties required to create/update an item.
Inherits from ItemBase; separated for clarity and future extension.
"""
pass


class Item(ItemBase):
"""
Item schema returned by the API.
Note: orm_mode is enabled to allow returning SQLAlchemy models directly.
"""
id: int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fastapi
uvicorn
sqlalchemy
pydantic