Skip to main content
In this lesson we’ll cover how to restrict GET endpoints so an authenticated user only retrieves their own posts. By default, if your GET /posts route returns all rows from the posts table, you’ll see entries from every user, for example:
Whether you return only the authenticated user’s posts or everyone’s public posts depends on your application. For example:
  • A private note-taking app should return only that user’s posts.
  • A social feed or public blog may return all public posts.
Below we show how to:
  1. Restrict list endpoints to the current user.
  2. Protect single-post retrieval.
  3. Revert to public behavior when appropriate.
First, here is the Postman screenshot showing a request to GET /posts that returns an empty array when filtering by the current user (this image is kept in place exactly as in the original lesson):
A screenshot of the Postman API client in dark mode showing a "fastapi-course" workspace with requests like Get Posts, Create Post, Delete Post, and the Authorization tab set to a Bearer token using {{JWT}}. The response pane shows a 200 OK status and an empty JSON array.

Quick endpoint decision guide


Ownership checks for delete (example)

When deleting a post you typically want to ensure only the owner can delete it. The example below shows a concise, correct implementation using SQLAlchemy and FastAPI:
This function:
  • Queries the post by id.
  • Returns 404 if not found.
  • Verifies ownership (post.owner_id == current_user.id).
  • Returns 403 if the authenticated user is not the owner.
  • Deletes only after the ownership check passes.

Filter GET /posts to return only the current user’s posts

A common mistake is filtering by the wrong column (e.g., posts.id instead of posts.owner_id) or forgetting to execute the query with .all(). Use this pattern to return only the authenticated user’s posts:
Common pitfalls:
  • Forgetting .all() returns a SQLAlchemy query object rather than a list, which will not serialize as JSON and may cause server errors.
  • Filtering on models.Post.id == current_user.id compares the post primary key to the user id and will typically return nothing or incorrect results.
Tip: When debugging, build the query into a variable and print it before calling .all() to inspect the generated SQL. Remove these prints in production.
Example for debugging:
A development server log illustrating the mistake of filtering by the wrong column might look like:
That log shows WHERE posts.id = ... — a sign you filtered on the wrong column.

Protect GET /posts/{id} to allow only the owner

To ensure only the owner can retrieve a single post, use the same ownership-check pattern as with delete:
With this in place, user A cannot access a post owned by user B; attempts return a 403 response:
Apply the same ownership checks to update endpoints (PUT/PATCH) as well as DELETE.

Reverting — make posts public again

If you want posts to be public (for a social feed), remove the ownership filter and return all posts:
To allow truly public (unauthenticated) access:
  • Remove the current_user dependency from the function signature altogether so a valid token is not required.
  • Or keep the authentication dependency but still return all posts if you want to know who is requesting (for logging, personalization, or rate limiting).
Choose behavior (private vs public) based on your app’s goals. Use ownership checks for private content and open endpoints for public content, while keeping security and auditing in mind.

Summary
  • To return only the authenticated user’s posts, filter by models.Post.owner_id == current_user.id and call .all() to execute the query.
  • Apply the same ownership verification to single-post retrieval and to mutation endpoints (update/delete).
  • Remove ownership checks if posts should be public; optionally remove authentication to allow unauthenticated access.
Links and references

Watch Video