Skip to content
Open
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
45 changes: 45 additions & 0 deletions crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from sqlalchemy import select
from sqlalchemy.orm import Session

import models
import schemas


def get_authors(db: Session) -> list[models.DBAuthor]:
return db.scalars(select(models.DBAuthor)).all()


def get_author_by_id(db: Session, author_id: int) -> models.DBAuthor | None:
return db.scalar(select(models.DBAuthor).where(models.DBAuthor.id == author_id))

def create_author(db: Session, data: schemas.AuthorCreate) -> models.DBAuthor:
new_author = models.DBAuthor(
name=data.name,
bio=data.bio
)
db.add(new_author)
db.commit()
db.refresh(new_author)
return new_author


def get_books(db: Session) -> list[models.DBBook]:
return db.scalars(select(models.DBBook)).all()


def get_book_by_id(db: Session, book_id: int) -> models.DBBook | None:
return db.scalar(select(models.DBBook).where(models.DBBook.id == book_id))


def create_book(db: Session, data: schemas.BookCreate, author_id: int) -> models.DBBook:
new_book = models.DBBook(
title=data.title,
summary=data.summary,
publication_date=data.publication_date,
author_id=author_id
)
db.add(new_book)
db.commit()
db.refresh(new_book)

return new_book
15 changes: 15 additions & 0 deletions database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import sessionmaker

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

engine = create_engine(
url=SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False}
)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

class Base(DeclarativeBase):
pass
Binary file added library.db
Binary file not shown.
69 changes: 69 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session

import models
import schemas
import crud
from database import SessionLocal, engine


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

app = FastAPI()


@app.get("/")
def root():
return "Hello World"


def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

@app.post("/create_author", response_model=schemas.AuthorBase)
def create_author(data: schemas.AuthorCreate, db: Session = Depends(get_db)):
return crud.create_author(db, data)

@app.get("/authors", response_model=list[schemas.AuthorRead])
def get_authors(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
authors = crud.get_authors(db)
return authors[skip: skip + limit]
Comment on lines +31 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /authors endpoint correctly implements pagination with skip/limit parameters. The /books endpoint should follow the same pattern.


@app.get("/author/{author_id}", response_model=schemas.AuthorRead)
def get_author_by_id(author_id: int, db: Session = Depends(get_db)):
author = crud.get_author_by_id(db=db, author_id=author_id)
if author is None:
raise HTTPException(status_code=404, detail=f"There is not author with id {author_id}")
return author


@app.post("/author/{author_id}/create_book", response_model=schemas.BookBase)
def create_book(author_id: int, data: schemas.BookCreate, db: Session = Depends(get_db)):
author = crud.get_author_by_id(db=db,author_id=author_id)
if author is None:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP status code should be 404 (Not Found): When an author doesn't exist, returning 400 is incorrect since this is a missing resource error, not a malformed request. Change to status_code=404.

raise HTTPException(status_code=404, detail="You can't create a book for this author, because this author doesn't exist!")
return crud.create_book(db=db, data=data, author_id=author_id)


@app.get("/book/{book_id}", response_model=schemas.BookRead)
def get_book_by_id(book_id: int, db: Session = Depends(get_db)):
book = crud.get_book_by_id(db=db, book_id=book_id)
if book is None:
raise HTTPException(status_code=404, detail="Book not found!")
return book

@app.get("/books", response_model=list[schemas.BookRead])
def get_books(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
books = crud.get_books(db=db)
return books[skip: skip + limit]

@app.get("/author/{author_id}/books", response_model=list[schemas.BookRead])
def get_books_by_author(author_id: int, skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
books = crud.get_books(db=db)
if author_id is not None:
books = [b for b in books if b.author_id == author_id]
return books[skip: skip + limit]
23 changes: 23 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from database import Base
from sqlalchemy import String, ForeignKey, Integer, Date
from sqlalchemy.orm import relationship, Mapped, mapped_column
from datetime import date

class DBAuthor(Base):
__tablename__ = "author_model"

id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String(100), nullable=False, unique=True)
bio: Mapped[str] = mapped_column(String(250))
books: Mapped[list["DBBook"]] = relationship(back_populates="author")


class DBBook(Base):
__tablename__ = "books_model"

id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
title: Mapped[str] = mapped_column(String(150), nullable=False, unique=True)
summary: Mapped[str] = mapped_column(String(200))
publication_date: Mapped[date] = mapped_column(Date())
author_id: Mapped[int] = mapped_column(ForeignKey("author_model.id"))
author: Mapped["DBAuthor"] = relationship(back_populates="books")
Binary file added requirements.txt
Binary file not shown.
31 changes: 31 additions & 0 deletions schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from pydantic import BaseModel
from typing import Optional
from datetime import date

class AuthorBase(BaseModel):
name: str
bio: Optional[str] = None

class AuthorCreate(AuthorBase):
pass

class AuthorRead(AuthorBase):
id: int

class Config:
from_attributes = True

class BookBase(BaseModel):
title: str
summary: str
publication_date: date

class BookCreate(BookBase):
pass

class BookRead(BookBase):
id: int
author_id: int

class Config:
from_attributes = True