A practical demonstration project built with FastAPI to showcase the fundamental differences, strengths, and use-cases of two major API paradigms: REST and GraphQL.
This application provides identical functionality through both a RESTful API and a GraphQL API, allowing developers to compare how each approach handles data fetching, mutations, and client-server interactions.
The main goal of this project is to serve as an educational tool and a boilerplate for understanding:
- How to implement both REST and GraphQL APIs within a single FastAPI application.
- The core philosophical differences between the two paradigms in a real-world context.
- When to choose one over the other based on practical examples.
- How to structure a production-ready application with concepts like services, repositories, dependency injection, and authentication.
The application is built around a simple movie archive domain, featuring three main entities:
- Director: Represents a film director.
- Movie: Represents a film, which has one director and can belong to multiple genres.
- Genre: Represents a film genre (e.g., Sci-Fi, Drama).
The project is organized into distinct, decoupled layers to ensure clean architecture and separation of concerns. The main app directory is split into two primary domains: rest and graphql, which share the core business logic, data models, and authentication mechanisms.
Follow these steps to get the project up and running on your local machine.
- Python 3.11+
- Poetry for dependency management.
- A running PostgreSQL database instance.
git clone https://github.com/hevalhazalkurt/fastapi-rest-vs-graphql.git
cd fastapi-rest-vs-graphql-showdownCreate an .env file in the project root by copying the example file. This file contains database connection strings and authentication keys.
cp .env_example .envNow, open the .env file and update the DATABASE_URL to match your local PostgreSQL credentials. Ensure this database exists on your PostgreSQL server.
# .env file content
# Update user, password, and db name
DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:PORT/DB_NAME
# Optional DB Pool Settings
POOL_SIZE=10
ECHO=False
MAX_OVERFLOW=2
# Static keys for simulated authentication
API_SECRET_KEY=fake_jwt_token
API_ADMIN_KEY=fake_admin_jwt_tokenUse the Makefile to install all required Python packages via Poetry.
make installRun the database migrations to create all the necessary tables (directors, movies, genres, etc.).
make migrateThe project includes a script to populate the database with a significant amount of sample data (directors, movies, and genres) for realistic testing. The data is read from data/dummy_data.csv.
make seedTo start the FastAPI application, use the following command. The server will be accessible at http://localhost:8000.
make run-localThis project exposes the same data through two different API endpoints. Authentication is handled via a static Bearer token.
- Admin Token: Use the
API_ADMIN_KEYfrom your.envfile (fake_admin_jwt_token) for operations requiring admin privileges (e.g.,POST,DELETE). - User Token: Use the
API_SECRET_KEY(fake_jwt_token) for standard read-only operations.
The REST API follows standard conventions with dedicated endpoints for each resource. Interactive Docs: Access the Swagger UI at http://localhost:8000/docs to explore all endpoints.
Example Requests:
Get all directors (Authentication required):
curl -X GET "http://localhost:8000/rest/directors/" \
-H "Authorization: Bearer fake_jwt_token"Create a new director (Admin scope required):
curl -X POST "http://localhost:8000/rest/directors/director" \
-H "Authorization: Bearer fake_admin_jwt_token" \
-H "Content-Type: application/json" \
-d '{"name": "Heval Hazal Kurt"}'The GraphQL API provides a single, powerful endpoint for all data operations.
Interactive Playground: Access the GraphiQL interface at http://localhost:8000/graphql to write and test queries.
Example Queries & Mutations:
Remember to set the Authorization: Bearer fake_jwt_token header in your GraphQL client.
Get directors:
query GetDirectorNames {
directors(limit: 5) {
name
}
}Get directors and their movies in a single request.
query GetDirectorsWithMovies {
directors(limit: 5) {
name
movies {
title
releaseYear
}
}
}Create a new director (Admin scope required). Remember to set the Authorization: Bearer fake_admin_jwt_token header in your GraphQL client.
mutation CreateNewDirector {
createDirector(directorInput: {name: "Greta Gerwig"}) {
uuid
name
}
}Here's a summary of the available make commands:
make install: Installs project dependencies.make migrate: Applies database migrations using Alembic.make seed: Populates the database with dummy data.make run-local: Starts the FastAPI development server.make static-checks: Runs Mypy for static type analysis.make lint: Checks code style with Ruff.make format: Formats code with Ruff.
This project is licensed under the MIT License.