From 8774b20cc1b81103c413fb85ecbfe9e5985fd1ca Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Thu, 18 Apr 2024 19:02:14 -0400 Subject: [PATCH 1/8] first commit --- api/main.py | 1 + api/schema/book.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/api/main.py b/api/main.py index 1e5369c..9f7c51c 100644 --- a/api/main.py +++ b/api/main.py @@ -56,6 +56,7 @@ 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 diff --git a/api/schema/book.py b/api/schema/book.py index 67327c5..8f62328 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -5,6 +5,7 @@ class BookBase(BaseModel): title: str author: str + genre: str publication_year: Optional[int] = None rating: Optional[int] = None @@ -22,6 +23,7 @@ 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 From e7f52a99d21fbfdcfd69067a514421e875b3e529 Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Thu, 18 Apr 2024 19:49:13 -0400 Subject: [PATCH 2/8] did first assignment, failing at GET author --- api/main.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/api/main.py b/api/main.py index 9f7c51c..c9aa13c 100644 --- a/api/main.py +++ b/api/main.py @@ -12,6 +12,17 @@ def get_next_book_id() -> int: book_id_counter += 1 return next_id +books.append( + Book( + title="Green Eggs and Ham", + author="Dr.Suess", + publication_year="1980", + genre="Self-help", + rating=10, + id=get_next_book_id() + ) +) + @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." @@ -39,6 +50,11 @@ async def get_book(book_id: int) -> Book: # What should the endpoint(s) be named? # 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/author/{author_last_name}", +) +async def get_book(author_last_name: str) -> Book: + return (Book for book in books if author_last_name in book.author) @app.post( "/books", @@ -80,3 +96,4 @@ async def brew(): status_code=status.HTTP_418_IM_A_TEAPOT, detail="Cannot brew coffee with a teapot!" ) + From 9856109816da22d14cd3d909668d7ad9542e225b Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Sat, 20 Apr 2024 12:31:39 -0400 Subject: [PATCH 3/8] added publication year --- api/main.py | 15 +++++++++------ api/schema/book.py | 5 ++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/api/main.py b/api/main.py index c9aa13c..b952f2c 100644 --- a/api/main.py +++ b/api/main.py @@ -16,7 +16,7 @@ def get_next_book_id() -> int: Book( title="Green Eggs and Ham", author="Dr.Suess", - publication_year="1980", + publication_year=1980, genre="Self-help", rating=10, id=get_next_book_id() @@ -50,11 +50,14 @@ async def get_book(book_id: int) -> Book: # What should the endpoint(s) be named? # 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/author/{author_last_name}", -) -async def get_book(author_last_name: str) -> Book: - return (Book for book in books if author_last_name in book.author) + +@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", diff --git a/api/schema/book.py b/api/schema/book.py index 8f62328..7372527 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -7,7 +7,10 @@ class BookBase(BaseModel): author: str genre: str publication_year: Optional[int] = None - rating: Optional[int] = None + #rating: Optional[int] = None + + def avg_rating(sum_of_ratings): -> float: + return # TODO # Add a 'genre' field here. You'll need to add it in a few other places as well! From 30c6d7b549fa120d5719370777012ac6a1280956 Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Sat, 20 Apr 2024 13:02:36 -0400 Subject: [PATCH 4/8] added rating and review schema --- api/schema/book.py | 7 ++++--- api/schema/rating.py | 6 ++++++ api/schema/review.py | 5 +++++ 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 api/schema/rating.py create mode 100644 api/schema/review.py diff --git a/api/schema/book.py b/api/schema/book.py index 7372527..181daf7 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -1,6 +1,7 @@ from typing import Optional - from pydantic import BaseModel +from schema.review import Rating +import statistics class BookBase(BaseModel): title: str @@ -9,8 +10,8 @@ class BookBase(BaseModel): publication_year: Optional[int] = None #rating: Optional[int] = None - def avg_rating(sum_of_ratings): -> float: - return + def avg_rating(sum_of_ratings) -> float: + return statistics.mean(sum_of_ratings) # TODO # Add a 'genre' field here. You'll need to add it in a few other places as well! diff --git a/api/schema/rating.py b/api/schema/rating.py new file mode 100644 index 0000000..ae6df3a --- /dev/null +++ b/api/schema/rating.py @@ -0,0 +1,6 @@ +from typing import Optional + +from pydantic import BaseModel, conint + +class Rating(BaseModel): + rating: conint(ge=0, le=5) \ No newline at end of file diff --git a/api/schema/review.py b/api/schema/review.py new file mode 100644 index 0000000..c54ec04 --- /dev/null +++ b/api/schema/review.py @@ -0,0 +1,5 @@ +from typing import Optional +from pydantic import BaseModel + +class review(BaseModel): + review: str \ No newline at end of file From 003c88d26b3bbef27bd5a363b620667b07da259f Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Sun, 21 Apr 2024 10:59:43 -0400 Subject: [PATCH 5/8] rating and review schema are functional --- api/schema/book.py | 2 +- api/schema/rating.py | 1 - api/schema/review.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/api/schema/book.py b/api/schema/book.py index 181daf7..977e1d5 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -1,6 +1,6 @@ from typing import Optional from pydantic import BaseModel -from schema.review import Rating +from .rating import Rating import statistics class BookBase(BaseModel): diff --git a/api/schema/rating.py b/api/schema/rating.py index ae6df3a..0ccd84b 100644 --- a/api/schema/rating.py +++ b/api/schema/rating.py @@ -1,5 +1,4 @@ from typing import Optional - from pydantic import BaseModel, conint class Rating(BaseModel): diff --git a/api/schema/review.py b/api/schema/review.py index c54ec04..a54a3bc 100644 --- a/api/schema/review.py +++ b/api/schema/review.py @@ -1,5 +1,5 @@ from typing import Optional from pydantic import BaseModel -class review(BaseModel): +class Review(BaseModel): review: str \ No newline at end of file From 1798ea6f7b0990c3161f294b7d649b78de271130 Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Tue, 23 Apr 2024 19:14:57 -0400 Subject: [PATCH 6/8] deleted rating, combined into review.py --- api/main.py | 17 +++++++++++++++-- api/schema/book.py | 17 ++++++++++------- api/schema/rating.py | 5 ----- api/schema/review.py | 6 ++++-- 4 files changed, 29 insertions(+), 16 deletions(-) delete mode 100644 api/schema/rating.py diff --git a/api/main.py b/api/main.py index b952f2c..857037e 100644 --- a/api/main.py +++ b/api/main.py @@ -19,7 +19,8 @@ def get_next_book_id() -> int: publication_year=1980, genre="Self-help", rating=10, - id=get_next_book_id() + id=get_next_book_id(), + review="Life changing. Inspiring. A true master piece on addition in the modern era." ) ) @@ -35,7 +36,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) @@ -51,6 +52,10 @@ 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) @@ -68,6 +73,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: BookCreate, book_title: str, book_review: str) -> Book: + 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}", ) @@ -79,6 +91,7 @@ async def update_book(book: BookCreate, book_id: int) -> Book: book_to_update.author = book.author book_to_update.publication_year = book.publication_year book_to_update.rating = book.rating + book_to_update.review = book.review else: book_to_update = Book.from_base(book, book_id) books.append(book_to_update) diff --git a/api/schema/book.py b/api/schema/book.py index 977e1d5..bbc4c3c 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -1,6 +1,6 @@ -from typing import Optional +from typing import Optional, List from pydantic import BaseModel -from .rating import Rating +from .review import Review import statistics class BookBase(BaseModel): @@ -8,11 +8,14 @@ class BookBase(BaseModel): author: str genre: str publication_year: Optional[int] = None - #rating: Optional[int] = None - - def avg_rating(sum_of_ratings) -> float: - return statistics.mean(sum_of_ratings) + review: List[Review] = [] + 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 + 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 @@ -30,7 +33,7 @@ def from_base(base: BookBase, id: int): genre = base.genre, author = base.author, publication_year = base.publication_year, - rating = base.rating + reviews = base.reviews ) diff --git a/api/schema/rating.py b/api/schema/rating.py deleted file mode 100644 index 0ccd84b..0000000 --- a/api/schema/rating.py +++ /dev/null @@ -1,5 +0,0 @@ -from typing import Optional -from pydantic import BaseModel, conint - -class Rating(BaseModel): - rating: conint(ge=0, le=5) \ No newline at end of file diff --git a/api/schema/review.py b/api/schema/review.py index a54a3bc..9754690 100644 --- a/api/schema/review.py +++ b/api/schema/review.py @@ -1,5 +1,7 @@ from typing import Optional -from pydantic import BaseModel +from pydantic import BaseModel, conint class Review(BaseModel): - review: str \ No newline at end of file + reviewer: Optional[str] = None + review: Optional[str] = None + rating: Optional[conint(ge=0, le=5)] = None \ No newline at end of file From b2eebd5e676402442b8a0fb610ef3615662f61c8 Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Thu, 25 Apr 2024 07:16:20 -0400 Subject: [PATCH 7/8] support for multiple reviews and ratings --- api/main.py | 19 ++++++++++--------- api/schema/book.py | 2 +- api/schema/review.py | 18 ++++++++++++++++-- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/api/main.py b/api/main.py index 857037e..daae05f 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() @@ -14,13 +15,13 @@ def get_next_book_id() -> int: books.append( Book( + id=get_next_book_id(), title="Green Eggs and Ham", author="Dr.Suess", publication_year=1980, genre="Self-help", - rating=10, - id=get_next_book_id(), - review="Life changing. Inspiring. A true master piece on addition in the modern era." + 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)], ) ) @@ -73,11 +74,11 @@ 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: BookCreate, book_title: str, book_review: str) -> Book: - 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/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( @@ -90,7 +91,7 @@ async def update_book(book: BookCreate, book_id: int) -> Book: 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.review = book.review else: book_to_update = Book.from_base(book, book_id) diff --git a/api/schema/book.py b/api/schema/book.py index bbc4c3c..7642bb9 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -8,7 +8,7 @@ class BookBase(BaseModel): author: str genre: str publication_year: Optional[int] = None - review: List[Review] = [] + reviews: List[Review] = [] def avg_rating(self) -> float: ratings = [review.rating for review in self.reviews if review.rating is not None] diff --git a/api/schema/review.py b/api/schema/review.py index 9754690..c77a35e 100644 --- a/api/schema/review.py +++ b/api/schema/review.py @@ -1,7 +1,21 @@ from typing import Optional from pydantic import BaseModel, conint -class Review(BaseModel): +class ReviewBase(BaseModel): reviewer: Optional[str] = None review: Optional[str] = None - rating: Optional[conint(ge=0, le=5)] = None \ No newline at end of file + 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 From ca4df705470240bcacd03dba72ee5f2d42e17a4c Mon Sep 17 00:00:00 2001 From: Nicholas Mackowski Date: Thu, 25 Apr 2024 19:16:38 -0400 Subject: [PATCH 8/8] added avg rating --- api/main.py | 2 +- api/schema/book.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/api/main.py b/api/main.py index daae05f..bd566e5 100644 --- a/api/main.py +++ b/api/main.py @@ -92,7 +92,7 @@ async def update_book(book: BookCreate, book_id: int) -> Book: book_to_update.author = book.author book_to_update.publication_year = book.publication_year book_to_update.rating = book.review.rating - book_to_update.review = book.review + book_to_update.reviews = book.reviews else: book_to_update = Book.from_base(book, book_id) books.append(book_to_update) diff --git a/api/schema/book.py b/api/schema/book.py index 7642bb9..f4d0bf2 100644 --- a/api/schema/book.py +++ b/api/schema/book.py @@ -1,5 +1,5 @@ from typing import Optional, List -from pydantic import BaseModel +from pydantic import BaseModel, computed_field from .review import Review import statistics @@ -10,11 +10,14 @@ class BookBase(BaseModel): publication_year: 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 - return statistics.mean(ratings) + else: + return statistics.mean(ratings) # TODO # Add a 'genre' field here. You'll need to add it in a few other places as well! @@ -33,7 +36,7 @@ def from_base(base: BookBase, id: int): genre = base.genre, author = base.author, publication_year = base.publication_year, - reviews = base.reviews + reviews = base.reviews, )