
This commit implements a simple movie database backend inspired by IMDb. It includes: - API endpoints for movies, actors, directors and genres - SQLAlchemy models with relationships - Alembic migrations - Pydantic schemas for request/response validation - Search and filtering functionality - Health check endpoint - Complete documentation
111 lines
3.0 KiB
Python
111 lines
3.0 KiB
Python
from typing import Any, Optional
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Path
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api import crud
|
|
from app.api.schemas.genre import (
|
|
Genre, GenreCreate, GenreUpdate, GenreDetails, GenreList
|
|
)
|
|
from app.db.session import get_db
|
|
|
|
router = APIRouter(prefix="/genres")
|
|
|
|
|
|
@router.get("", response_model=GenreList)
|
|
def read_genres(
|
|
db: Session = Depends(get_db),
|
|
skip: int = Query(0, ge=0),
|
|
limit: int = Query(100, ge=1, le=100),
|
|
name: Optional[str] = None,
|
|
movie_id: Optional[int] = None,
|
|
) -> Any:
|
|
"""
|
|
Retrieve all genres with optional filtering.
|
|
"""
|
|
# Build filter dict from query parameters
|
|
filters = {}
|
|
if name:
|
|
filters["name"] = name
|
|
if movie_id:
|
|
filters["movie_id"] = movie_id
|
|
|
|
genres, total = crud.genre.get_multi(db, skip=skip, limit=limit, filters=filters)
|
|
return {"data": genres, "total": total}
|
|
|
|
|
|
@router.post("", response_model=Genre, status_code=201)
|
|
def create_genre(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
genre_in: GenreCreate,
|
|
) -> Any:
|
|
"""
|
|
Create a new genre.
|
|
"""
|
|
# Check if a genre with this name already exists
|
|
existing_genre = crud.genre.get_by_name(db, name=genre_in.name)
|
|
if existing_genre:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Genre with name {genre_in.name} already exists"
|
|
)
|
|
|
|
genre = crud.genre.create(db, genre_in=genre_in)
|
|
return genre
|
|
|
|
|
|
@router.get("/{genre_id}", response_model=GenreDetails)
|
|
def read_genre(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
genre_id: int = Path(..., ge=1),
|
|
) -> Any:
|
|
"""
|
|
Get a specific genre by ID.
|
|
"""
|
|
genre = crud.genre.get(db, genre_id=genre_id)
|
|
if not genre:
|
|
raise HTTPException(status_code=404, detail="Genre not found")
|
|
return genre
|
|
|
|
|
|
@router.put("/{genre_id}", response_model=Genre)
|
|
def update_genre(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
genre_id: int = Path(..., ge=1),
|
|
genre_in: GenreUpdate,
|
|
) -> Any:
|
|
"""
|
|
Update a genre.
|
|
"""
|
|
genre = crud.genre.get(db, genre_id=genre_id)
|
|
if not genre:
|
|
raise HTTPException(status_code=404, detail="Genre not found")
|
|
|
|
# Check if another genre with the new name already exists
|
|
if genre_in.name and genre_in.name != genre.name:
|
|
existing_genre = crud.genre.get_by_name(db, name=genre_in.name)
|
|
if existing_genre:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Genre with name {genre_in.name} already exists"
|
|
)
|
|
|
|
genre = crud.genre.update(db, db_genre=genre, genre_in=genre_in)
|
|
return genre
|
|
|
|
|
|
@router.delete("/{genre_id}", status_code=204, response_model=None)
|
|
def delete_genre(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
genre_id: int = Path(..., ge=1),
|
|
) -> Any:
|
|
"""
|
|
Delete a genre.
|
|
"""
|
|
success = crud.genre.delete(db, genre_id=genre_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Genre not found")
|
|
return None |