Skip to content

Commit db03c97

Browse files
committed
implement CRUD API for books
1 parent 3707dd2 commit db03c97

File tree

3 files changed

+109
-3
lines changed

3 files changed

+109
-3
lines changed

main.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
from fastapi import FastAPI
22
from dotenv import dotenv_values
3+
from pymongo import MongoClient
4+
from routes import router as book_router
5+
36
config = dotenv_values(".env")
47

58
app = FastAPI()
69

7-
@app.get("/")
8-
async def root():
9-
return {"message": "Hello World"}
10+
@app.on_event("startup")
11+
def startup_db_client():
12+
app.mongodb_client = MongoClient(config["ATLAS_URI"])
13+
app.database = app.mongodb_client[config["DB_NAME"]]
14+
15+
@app.on_event("shutdown")
16+
def shutdown_db_client():
17+
app.mongodb_client.close()
1018

19+
app.include_router(book_router, tags=["books"], prefix="/book")
1120

models.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import uuid
2+
from typing import Optional
3+
from pydantic import BaseModel, Field
4+
5+
class Book(BaseModel):
6+
id: str = Field(default_factory=uuid.uuid4, alias="_id")
7+
title: str = Field(...)
8+
author: str = Field(...)
9+
synopsis: str = Field(...)
10+
11+
class Config:
12+
allow_population_by_field_name = True
13+
schema_extra = {
14+
"example": {
15+
"title": "Don Quixote",
16+
"author": "Miguel de Cervantes",
17+
"synopsis": "..."
18+
}
19+
}
20+
21+
22+
class BookUpdate(BaseModel):
23+
title: str = Field(...)
24+
author: str = Field(...)
25+
synopsis: str = Field(...)
26+
27+
class Config:
28+
schema_extra = {
29+
"example": {
30+
"title": "Don Quixote",
31+
"author": "Miguel de Cervantes",
32+
"synopsis": "Don Quixote is a Spanish novel by Miguel de Cervantes..."
33+
}
34+
}

routes.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from fastapi import APIRouter, Body, Request, Response, HTTPException, status
2+
from fastapi.encoders import jsonable_encoder
3+
4+
from models import Book, BookUpdate
5+
6+
router = APIRouter()
7+
8+
@router.post("/", response_description="Create a new book", status_code=status.HTTP_201_CREATED)
9+
def create_book(request: Request, book: Book = Body(...)):
10+
book = jsonable_encoder(book)
11+
new_book = request.app.database["books"].insert_one(book)
12+
created_book = request.app.database["books"].find_one(
13+
{"_id": new_book.inserted_id}
14+
)
15+
16+
return created_book
17+
18+
19+
@router.get("/", response_description="List all books")
20+
def list_books(request: Request):
21+
books = list(request.app.database["books"].find(limit=100))
22+
return books
23+
24+
@router.get("/{id}", response_description="Get a single book by id")
25+
def find_book(id: str, request: Request):
26+
if (book := request.app.database["books"].find_one({"_id": id})) is not None:
27+
return book
28+
29+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Book with ID {id} not found")
30+
31+
32+
@router.put("/{id}", response_description="Update a book")
33+
def update_book(id: str, request: Request, book: BookUpdate = Body(...)):
34+
book = {k: v for k, v in book.dict().items() if v is not None}
35+
36+
if len(book) >= 1:
37+
update_result = request.app.database["books"].update_one(
38+
{"_id": id}, {"$set": book}
39+
)
40+
41+
if update_result.modified_count == 1:
42+
if (
43+
updated_book := request.app.database["books"].find_one({"_id": id})
44+
) is not None:
45+
return updated_book
46+
47+
if (
48+
existing_book := request.app.database["books"].find_one({"_id": id})
49+
) is not None:
50+
return existing_book
51+
52+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Book with ID {id} not found")
53+
54+
55+
@router.delete("/{id}", response_description="Delete a book")
56+
def delete_book(id: str, request: Request, response: Response):
57+
delete_result = request.app.database["books"].delete_one({"_id": id})
58+
59+
if delete_result.deleted_count == 1:
60+
response.status_code = status.HTTP_204_NO_CONTENT
61+
return response
62+
63+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Book with ID {id} not found")

0 commit comments

Comments
 (0)