REST API for managing personal bookmarks (title, link, category). PostgreSQL database with async SQLAlchemy, containerized with Docker Compose. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
import uuid
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database import get_db
|
|
from app.models import Bookmark
|
|
from app.schemas import BookmarkCreate, BookmarkResponse, BookmarkUpdate
|
|
|
|
router = APIRouter(prefix="/api/bookmarks", tags=["bookmarks"])
|
|
|
|
|
|
@router.get("/", response_model=list[BookmarkResponse])
|
|
async def list_bookmarks(
|
|
category: str | None = None, db: AsyncSession = Depends(get_db)
|
|
):
|
|
query = select(Bookmark).order_by(Bookmark.created_at.desc())
|
|
if category:
|
|
query = query.where(Bookmark.category == category)
|
|
result = await db.execute(query)
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.get("/{bookmark_id}", response_model=BookmarkResponse)
|
|
async def get_bookmark(bookmark_id: uuid.UUID, db: AsyncSession = Depends(get_db)):
|
|
result = await db.execute(select(Bookmark).where(Bookmark.id == bookmark_id))
|
|
bookmark = result.scalar_one_or_none()
|
|
if not bookmark:
|
|
raise HTTPException(status_code=404, detail="Bookmark not found")
|
|
return bookmark
|
|
|
|
|
|
@router.post("/", response_model=BookmarkResponse, status_code=201)
|
|
async def create_bookmark(data: BookmarkCreate, db: AsyncSession = Depends(get_db)):
|
|
bookmark = Bookmark(**data.model_dump())
|
|
db.add(bookmark)
|
|
await db.commit()
|
|
await db.refresh(bookmark)
|
|
return bookmark
|
|
|
|
|
|
@router.put("/{bookmark_id}", response_model=BookmarkResponse)
|
|
async def update_bookmark(
|
|
bookmark_id: uuid.UUID, data: BookmarkUpdate, db: AsyncSession = Depends(get_db)
|
|
):
|
|
result = await db.execute(select(Bookmark).where(Bookmark.id == bookmark_id))
|
|
bookmark = result.scalar_one_or_none()
|
|
if not bookmark:
|
|
raise HTTPException(status_code=404, detail="Bookmark not found")
|
|
for field, value in data.model_dump(exclude_unset=True).items():
|
|
setattr(bookmark, field, value)
|
|
await db.commit()
|
|
await db.refresh(bookmark)
|
|
return bookmark
|
|
|
|
|
|
@router.delete("/{bookmark_id}", status_code=204)
|
|
async def delete_bookmark(bookmark_id: uuid.UUID, db: AsyncSession = Depends(get_db)):
|
|
result = await db.execute(select(Bookmark).where(Bookmark.id == bookmark_id))
|
|
bookmark = result.scalar_one_or_none()
|
|
if not bookmark:
|
|
raise HTTPException(status_code=404, detail="Bookmark not found")
|
|
await db.delete(bookmark)
|
|
await db.commit()
|