diff --git a/api/main.py b/api/main.py index 1e5369c..bd566e5 100644 --- a/api/main.py +++ b/api/main.py @@ -1,5 +1,6 @@ from fastapi import FastAPI, HTTPException, status from schema.book import Book, BookCreate +from schema.review import Review, ReviewCreate app = FastAPI() @@ -12,6 +13,18 @@ def get_next_book_id() -> int: book_id_counter += 1 return next_id +books.append( + Book( + id=get_next_book_id(), + title="Green Eggs and Ham", + author="Dr.Suess", + publication_year=1980, + genre="Self-help", + reviews=[Review(id=1,reviewer="LeBron James", review="Life changing. A true masterpiece.", rating=5), + Review(id=2,reviewer="LeBron James", review="Read it again. Mid.", rating=3)], + ) +) + @app.get("/") async def root(): return "The root endpoint of a service (/) is often used as a health check to determine whether the service is working or not." @@ -24,7 +37,7 @@ async def get_books(): return books @app.get( - "/books/{book_id}", +"/books/{book_id}", ) async def get_book(book_id: int) -> Book: ret = next((book for book in books if book.id == book_id), None) @@ -40,6 +53,18 @@ async def get_book(book_id: int) -> Book: # Will it/they return one or potentially several books? # Can you safely handle the case where no books are returned? What HTTP status code would that be? +# @app.get("/books/bookreviews/{book_reviews}") +# async def get_book_reviews(book_reviws: str) -> list[Book]: +# return(book_review for book in books if ) + +@app.get("/books/author/{author_last_name}") +async def get_book_author(author_last_name: str) -> list[Book]: + return (book for book in books if author_last_name in book.author) + +@app.get("/books/publication_year/{publication_year}") +async def get_book_publication_year(publication_year: int) -> list[Book]: + return (book for book in books if publication_year == book.publication_year) + @app.post( "/books", status_code=status.HTTP_201_CREATED, @@ -49,6 +74,13 @@ async def create_book(book: BookCreate) -> Book: books.append(new_book) return new_book +# @app.put("/books/bookreview/{book_review}",) +# async def post_book_reviews(book_title:BookBase,_review: ReviewCreate) -> Review: +# book_to_update = next((book for book in books if book_title == book.title), None) +# if book_title in book.title: +# book.review.append(book_review) + + @app.put( "/books/{book_id}", ) @@ -56,9 +88,11 @@ async def update_book(book: BookCreate, book_id: int) -> Book: book_to_update = next((book for book in books if book.id == book_id), None) if book_to_update: book_to_update.title = book.title + book_to_update.genre = book.genre book_to_update.author = book.author book_to_update.publication_year = book.publication_year - book_to_update.rating = book.rating + book_to_update.rating = book.review.rating + book_to_update.reviews = book.reviews else: book_to_update = Book.from_base(book, book_id) books.append(book_to_update) @@ -79,3 +113,4 @@ async def brew(): status_code=status.HTTP_418_IM_A_TEAPOT, detail="Cannot brew coffee with a teapot!" ) + diff --git a/api/schema/book.py b/api/schema/book.py index 67327c5..f4d0bf2 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -1,13 +1,24 @@ -from typing import Optional - -from pydantic import BaseModel +from typing import Optional, List +from pydantic import BaseModel, computed_field +from .review import Review +import statistics class BookBase(BaseModel): title: str author: str + genre: str publication_year: Optional[int] = None - rating: Optional[int] = None + reviews: List[Review] = [] + @computed_field + @property + def avg_rating(self) -> float: + ratings = [review.rating for review in self.reviews if review.rating is not None] + if not ratings: + return 0.0 + else: + return statistics.mean(ratings) + # TODO # Add a 'genre' field here. You'll need to add it in a few other places as well! # Bonus: try implementing genre as an enum rather than a string @@ -22,9 +33,10 @@ def from_base(base: BookBase, id: int): return Book( id = id, title = base.title, + genre = base.genre, author = base.author, publication_year = base.publication_year, - rating = base.rating + reviews = base.reviews, ) diff --git a/api/schema/review.py b/api/schema/review.py new file mode 100644 index 0000000..c77a35e --- /dev/null +++ b/api/schema/review.py @@ -0,0 +1,21 @@ +from typing import Optional +from pydantic import BaseModel, conint + +class ReviewBase(BaseModel): + reviewer: Optional[str] = None + review: Optional[str] = None + rating: Optional[conint(ge=0, le=5)] = None + +class ReviewCreate(ReviewBase): + pass + +class Review(ReviewBase): + id: int + + def from_base(base: ReviewBase, id: int): + return Review( + id = id, + reviewer = base.reviewer, + rewview = base.review, + rating = base.rating + ) \ No newline at end of file