This article explains how to modify FastAPI endpoints to retrieve only posts created by the authenticated user.
In this lesson, we address a common issue encountered when retrieving posts from an authenticated route. By default, accessing the endpoint returns posts from all users, as shown in the sample JSON response below:
Copy
Ask AI
[ { "title": "this is the new title", "content": "this is the new content", "published": true, "id": 4, "created_at": "2021-08-28T21:18:13.460585-04:00", "owner_id": 21 }, { "title": "top beaches in florida", "content": "something somethng beaches", "published": true, "id": 9, "created_at": "2021-08-28T21:48:30.323507-04:00", "owner_id": 23 }]
Depending on your application, this behavior might not be desirable. For example, in a private note-taking app, you would only want to retrieve posts created by the currently logged-in user. Conversely, in a public social media application, displaying all posts might be acceptable.Below, we outline how to modify your FastAPI endpoints to ensure that only posts belonging to the authenticated user are returned. This same approach can be applied when fetching a single post—ensuring that only its creator can access it.
Modifying the GET Endpoint to Filter by Authenticated User
To restrict the results to only the posts created by the authenticated user, add a filter using current_user.id. The updated GET endpoint looks like this:
Copy
Ask AI
from .database import get_dbfrom fastapi import APIRouter, Depends, HTTPException, statusfrom sqlalchemy.orm import Sessionfrom typing import Listimport models, schemas, oauth2router = APIRouter( prefix="/posts", tags=['Posts'])@router.get("/", response_model=List[schemas.Post])def get_posts(db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user)): # Filter posts by the owner_id to return only posts belonging to the current user posts = db.query(models.Post).filter(models.Post.owner_id == current_user.id).all() return posts@router.post("/", status_code=status.HTTP_201_CREATED, response_model=schemas.Post)def create_posts(post: schemas.PostCreate, db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user)): # Here you would typically create a new post. return post
If you’re logged in as user with ID 23, a GET request to the posts endpoint now returns only posts with owner_id: 23. For example:
Copy
Ask AI
[ { "title": "asdf", "content": "sdfsdf", "published": true, "id": 10, "created_at": "2021-08-28T21:49:28.150019-04:00", "owner_id": 23 }, { "title": "this is the new title wahoo", "content": "this is the new content", "published": true, "id": 9, "created_at": "2021-08-28T21:49:30.323570-04:00", "owner_id": 23 }]
Similarly, if a different user (for example, user ID 21) is authenticated, only that user’s posts will be returned.
For single post retrieval, apply similar logic to verify that only the owner can access the post. This ensures robust security and proper access control.
The following example demonstrates how to retrieve an individual post while ensuring proper error handling when a post is not found:
Copy
Ask AI
@router.get("/{id}", response_model=schemas.Post)def get_post(id: int, db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user)): # Retrieve the post by its ID post = db.query(models.Post).filter(models.Post.id == id).first() if not post: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Post with id: {id} was not found") return post@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)def delete_post(id: int, db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user)): # Deletion logic would be similar in checking ownership before deleting pass
During testing, you may encounter log outputs that help debug SQL queries. For example, you might temporarily print out the SQL query generated by SQLAlchemy:
INFO: SELECT posts.id AS posts_id, posts.title AS posts_title, ...INFO: FROM postsINFO: WHERE posts.id IN (id1s)
Be cautious when using post IDs for filtering. Ensure that you are comparing the owner_id with the current user’s ID to guarantee that only authorized data is retrieved.
If your application’s requirements evolve (for example, switching to a social media style where all posts are public), you can simply remove the ownership filter:
This lesson demonstrates how to adjust your FastAPI endpoints to either restrict data access to the authenticated user or allow public access, based on your application’s needs. By filtering posts using current_user.id and incorporating proper error handling, you improve both security and user experience.For further reading on FastAPI and SQLAlchemy best practices, check out the following resources: