Why Choose GraphQL and Strawberry over REST?
If you’ve ever built REST APIs for real-world projects, you’ve likely encountered a scenario where the frontend needs to display a user’s name along with their three latest posts. With REST, you usually have to call two separate APIs or modify the /user endpoint to cram in extra post data. The first approach wastes network round-trips, while the second makes the API bloated and hard to maintain.
GraphQL solves this problem by allowing clients to define exactly what data they need. Previously, implementing GraphQL in Python was quite cumbersome with Graphene. However, after switching to Strawberry, things became much easier. This library fully leverages modern Python Type Hints, making code clean, easy to debug, and providing excellent support for IDEs like VS Code or PyCharm.
In a dashboard project handling about 2,000 requests per second, combining Strawberry and FastAPI helped me reduce development time by 30%. Instead of defining dozens of small REST endpoints, I could focus solely on the Schema. System performance was also maintained thanks to the asynchronous mechanism supported by both libraries.
Environment Setup
You should use Python 3.9 or higher to make the most of type-related features. We will install FastAPI as the web framework and the FastAPI-supported version of Strawberry.
# Initialize virtual environment
python -m venv venv
source venv/bin/activate
# Install libraries
pip install "strawberry-graphql[fastapi]" uvicorn fastapi
I’m also installing uvicorn to serve as the ASGI server. This is the standard choice for running async Python applications in production environments today.
Schema Design: Thinking in Types
In the world of GraphQL, the Schema is the most critical component. Instead of worrying about URLs, we define “Types”. Suppose you’re building a book management app; start with the @strawberry.type decorator.
import strawberry
from typing import List, Optional
@strawberry.type
class Book:
id: int
title: str
author: str
price: float
# Mock data
BOOKS_DB = [
Book(id=1, title="Python Programming", author="IT Admin", price=150.0),
Book(id=2, title="GraphQL Basics", author="Strawberry Fan", price=200.0),
]
@strawberry.type
class Query:
@strawberry.field
def books(self) -> List[Book]:
return BOOKS_DB
@strawberry.field
def book_by_id(self, id: int) -> Optional[Book]:
return next((book for book in BOOKS_DB if book.id == id), None)
A major advantage of Strawberry is its use of pure Python Type Hints. You don’t need to learn a new syntax for type declarations. If you’re already familiar with Pydantic, picking up Strawberry will take only a few minutes.
Integrating with FastAPI
Once the Schema is ready, you need to expose it on an endpoint for client access. Strawberry provides GraphQLRouter, making FastAPI integration incredibly simple.
from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter
# Initialize Schema
schema = strawberry.Schema(query=Query)
graphql_app = GraphQLRouter(schema)
app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Run the file and visit http://localhost:8000/graphql to see the GraphiQL interface. Here, you can test queries directly without needing Postman or Insomnia.
Solving the N+1 Problem for Performance Optimization
The N+1 error is a silent performance killer in GraphQL. For example, when fetching a list of 10 books, if you call the database once for each book to retrieve the author’s name, the system executes a total of 11 queries. This is extremely resource-intensive.
The best solution is using a DataLoader. This mechanism batches all required IDs and performs a single SQL query with a WHERE id IN (...) condition.
from strawberry.dataloader import DataLoader
async def load_authors(keys: List[int]) -> List[str]:
# Execute only one query for all keys
author_map = {1: "John Doe", 2: "Jane Smith"}
return [author_map.get(key, "Unknown") for key in keys]
author_loader = DataLoader(load_fn=load_authors)
@strawberry.type
class BookWithLoader:
id: int
author_id: int
@strawberry.field
async def author_name(self) -> str:
return await author_loader.load(self.author_id)
Applying DataLoader helped me reduce the latency of a report page from 5 seconds to less than 200ms. This is a must-know technique if you want to work with large datasets.
Monitoring and Operations
How do you know if your API is performing well? With FastAPI, you should add middleware to log the execution time of each request. Strawberry also supports Extensions for integrating Apollo Tracing or Sentry.
Never push an API to production without monitoring tools. Tracking which queries are consuming resources will help you optimize the system in time. The combination of Strawberry’s strictness and FastAPI’s speed creates a powerful backend system that makes frontend teams much more efficient.

