β Adding a New Endpoint
We are going to add another endpoint to our application:
ποΈ main.py
@app.get("/")
async def read_all(db: db_dependency)
return db.query(Todos).all()
@app.get("/todo/{todo_id}")
async def read_todo(db : db_dependency, todo_id:int):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()π Why .first() Is Important
The .first() method is used because our application does not know how many records in the todos table might match the provided path parameter.
As soon as a matching record is found, we want to return that data immediately instead of scanning the entire table.
Since the ID is a primary key, it should be unique and non-duplicated.
β οΈ Handling Missing Records
Before enhancing the endpoint, ensure all necessary imports are included.
ποΈ main.py
from typing import Annotated
from fastapi import FastAPI, Depends, HTTPException, Path # π Path & HTTPException added
from sqlalchemy.orm import Session
from starlette import status # π For HTTP status codes
import models
from models import Todos # π Your Todo model
from database import engine, SessionLocalπ§ Why These Imports Matter
Dependsβ Enables dependency injectionSessionβ Allows interaction with the databaseHTTPExceptionβ Raises controlled errorsPathβ Adds validation to path parametersstatusβ Provides readable HTTP status constants
π Enhancing the endpoint
We now enhance the endpoint to handle cases where a todo does not exist:
ποΈ main.py
@app.get("/")
async def read_all(db: db_dependency)
return db.query(Todos).all()
@app.get("/todo/{todo_id}")
async def read_todo(db : db_dependency, todo_id:int):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is not None:
return todo_model
else:
raise HTTPException(status_code=404, detail='Todo Not Found')π₯οΈ Running the Application
Now, open your terminal and start the FastAPI server:
uvicorn main:app --reloadπ Testing in the Browser
Next, open your browser:
Here, you will see the available GET request endpoints:
/Read All
/todo/{todo_id} β Read Todo
Try fetching records with IDs 1, 2, and 3, and also test an ID that does not exist.
β Adding a Success Status Code
Now, letβs enhance the endpoint by explicitly defining the success status code and adding validation for the path parameter:
ποΈ main.py
@app.get("/todo/{todo_id}", status_code=status.HTTP_200_OK)
async def read_todo(db : db_dependency, todo_id:int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is not None:
return todo_model
else:
raise HTTPException(status_code=4040, detail='Todo Not Found')π§© Adding a Status Code to the First Endpoint
We will also explicitly define the status code for the read_all endpoint:
ποΈ main.py
@app.get("/", status_code=status.HTTP_200_OK)
async def read_all(db: db_dependency):
return db.query(Todos).all()
@app.get("/todo/{todo_id}", status_code=status.HTTP_200_OK)
async def read_todo(db : db_dependency, todo_id:int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is not None:
return todo_model
else:
raise HTTPException(status_code=404, detail='Todo Not Found')π Testing in the Browser
Letβs confirm that the status codes work as expected.
Refresh your browser. In case the server did not reload you can always start it up.
uvicorn main: app --reloadποΈ main.py
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from fastapi import FastAPI, Path, Depends, HTTPException
from starlette import status
import models
from models import Todos
from database import engine, SessionLocal
app = FastAPI()
models.Base.metadata.create_all(bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
@app.get("/", status_code=status.HTTP_200_OK)
async def read_all(db: db_dependency):
return db.query(Todos).all()
@app.get("/todo/{todo_id}", status_code=status.HTTP_200_OK)
async def read_todo(db : db_dependency, todo_id:int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is not None:
return todo_model
else:
raise HTTPException(status_code=404, detail='Todo Not Found')
No Changes in models.py and database.py