Get Expense by ID
Add an endpoint that retrieves a single expense using a path parameter
Writing code and entering commands is only available on desktop. Open this page on a larger screen to complete this chapter.
Why you need a single-expense endpoint
The GET /expenses endpoint returns every expense in the tracker. That works for displaying a full list, but a client often needs just one record. For example, a details screen needs to fetch a specific expense, or a confirmation dialog needs to show what the user is about to delete.
The path parameter {expense_id} captures the identifier from the URL. FastAPI converts it to the declared type (int) automatically. If the identifier does not match any stored expense, you raise an HTTPException with status code 404.
Note: the import line changes in this chapter. HTTPException is added to the fastapi import.
Instructions
- Add the
@app.get("/expenses/{expense_id}")decorator. - Define a function named
get_expensewith anexpense_idparameter of typeint. - If
expense_idis not inexpenses, raiseHTTPException(status_code=404, detail="Expense not found"). - Return
expenses[expense_id].
from datetime import datetime
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field, field_validator
from typing import Literal, Optional
app = FastAPI()
class Expense(BaseModel):
description: str = Field(min_length=1)
amount: float = Field(gt=0)
category: Literal["food", "transport", "entertainment", "utilities", "other"]
date: Optional[str] = None
@field_validator("date")
@classmethod
def validate_date_format(cls, v):
if v is not None:
try:
datetime.strptime(v, "%Y-%m-%d")
except ValueError:
raise ValueError("Date must be in YYYY-MM-DD format")
return v
expenses = {}
counter = 0
@app.post("/expenses", status_code=201)
def create_expense(expense: Expense):
global counter
counter += 1
expenses[counter] = {"id": counter, **expense.model_dump()}
return expenses[counter]
@app.get("/expenses")
def list_expenses(category: str = None):
if category:
return [e for e in expenses.values() if e["category"] == category]
return list(expenses.values())
# Step 1: Add @app.get("/expenses/{expense_id}")
# Step 2: Define get_expense with expense_id: int
# Step 3: If expense_id not in expenses, raise HTTPException(status_code=404, detail="Expense not found")
# Step 4: Return expenses[expense_id]
Interactive Code Editor
Sign in to write and run code, track your progress, and unlock all chapters.
Sign In to Start Coding