FastAPI - Beginner to Pro / Project 2- Move Fast With FastAPI

Delete Book with Delete Request

❌ Creating a DELETE Endpoint to Remove a Book

In this phase, we will create a DELETE HTTP endpoint that allows users to remove a book from the system using its unique identifier.

In RESTful API design:

  • GET → Retrieve data

  • POST → Create data

  • PUT → Update data

  • DELETE → Remove data

👉 Here, we are implementing the DELETE operation.


🧱 Define the DELETE Endpoint

@app.delete("/books/{book_id}") # uses a path parameter.
async def delete_book(book_id: int):
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book_id:
            BOOKS.pop(i)
            break

🔍 Understanding the DELETE Route

1️⃣ Route Definition

@app.delete("/books/{book_id}")

👉 {book_id} is a path parameter taken from the URL.

Example:

DELETE /books/4

FastAPI extracts and passes:

book_id = 4

2️⃣ book_id: int

Since it’s typed as int:

  • FastAPI converts the value automatically

  • If it’s not an integer → returns HTTP 422

  • Validation happens before the function runs

3️⃣ Loop Through BOOKS

for i in range(len(BOOKS)):

We use the index because removing an item requires its position in the list.

4️⃣ Find and Delete

if BOOKS[i].id == book_id:
    BOOKS.pop(i)

👉 If IDs match, the book is removed.

5️⃣ break

After deletion:

👉 Exit the loop immediately to avoid unnecessary work.


🧠 Backend Fundamental Insight

Let’s understand what happens internally when a DELETE request is made:

  1. The client sends a DELETE request.

  2. FastAPI matches the route.

  3. It extracts and validates book_id.

  4. Your function executes.

  5. The book is removed from in-memory storage.

  6. The response is returned.

⚠️ Important:

Right now, this uses an in-memory list (BOOKS).

If the server restarts:

  • All data is lost.

  • In real-world systems, this would interact with a database.

Understanding this difference is critical when learning backend development.


🌐 Testing the Endpoint in the Browser

👉 Open Swagger UI in your browser.

Step-by-step:

  1. Locate the DELETE /books/{book_id} endpoint.

  2. Click Try it out.

  3. Enter:

4
  1. Click Execute.

You should see that:

  • The book with ID 4 is removed.

  • A subsequent GET request will no longer return it.


🗂️ books2.py

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Book:
    id: int
    title: str
    author: str
    description: str
    rating: int
    
    def __init__(self, id, title, author, description, rating):
        self.id = id
        self.title = title
        self.author = author
        self.description = description
        self.rating = rating 

class BookRequest(BaseModel):
    id: Optional[int] = Field(description="ID is not required", default=None)
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0, lt=6)

    model_config = { 
        "json_schema_extra": {
            "example": {
                "title": "A new book",
                "author": "Name of the author",
                "description": "The description of the book",
                "rating": 5
            }
        }
    }

BOOKS = [
    Book(1, 'Computer Science Pro', 'codingwithrobby', 'A very nice book', 3),
    Book(2, 'Be Fast with FastAPI', 'codingwithrobby', 'A great book', 5),
    Book(3, 'Master Endpoints', 'codingwithrobby', 'An awesome book', 5),
    Book(4, 'HP1', 'Author 1', 'Book Description', 2),
    Book(5, 'HP2', 'Author 2', 'Book Description', 3),
    Book(6, 'HP3', 'Author 3', 'Book Description', 1)
]

@app.get("/books")
async def read_all_books():
    return BOOKS

@app.post("/create_book")
async def create_book(book_request: BookRequest):
    new_book = Book(**book_request.model_dump())
    BOOKS.append(find_book_id(new_book))

def find_book_id(book: Book):
    if len(BOOKS) > 0:
        book.id = BOOKS[-1].id + 1
    else:
        book.id = 1
    return book
    
@app.get("/books/{book_id}") 
async def read_book(book_id: int):
    for book in BOOKS:
        if book.id == book_id:
            return book

@app.get("/books/")
async def read_book_by_rating(book_rating: int):
    books_to_return = []
    for book in BOOKS:
        if book.rating == book_rating:
            books_to_return.append(book)
    return books_to_return
    
@app.put("/books/update_book")
async def update_book(book: BookRequest):
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book.id:
            BOOKS[i] = book
            
@app.delete("/books/{book_id}")
async def delete_book(book_id: int):
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book_id:
            BOOKS.pop(i)
            break
            
 def find_book_id(book: Book):
    book.id = 1 if len(BOOKS) == 0 else BOOKS[-1].id + 1
    return book