GraphQL in Python with Strawberry: A Practical Guide
Learn to build production-ready GraphQL APIs in Python using Strawberry.
20+ years shipping production Python across data and backend systems. Drawn from code that ran under real load.
- ✓Basic knowledge of Python (functions, classes, type hints)
- ✓Familiarity with GraphQL concepts (queries, mutations, subscriptions)
- ✓Python 3.8+ installed
- ✓Basic understanding of async/await
- Strawberry is a modern Python library for building GraphQL APIs with type hints.
- Define schema using Python classes decorated with @strawberry.type.
- Resolvers are methods on types; mutations use @strawberry.mutation.
- Supports subscriptions via async generators.
- Integrates with Django, Flask, FastAPI, and ASGI servers.
Imagine you're at a restaurant. REST is like ordering from a fixed menu: you get a full plate even if you only want a side. GraphQL is like a custom buffet where you tell the chef exactly which ingredients you want. Strawberry is the chef's assistant that helps you prepare that custom meal in Python.
GraphQL has revolutionized API development by giving clients the power to request exactly the data they need. In the Python ecosystem, Strawberry stands out as a modern, type-hint-driven library that makes building GraphQL APIs intuitive and safe. Unlike older libraries like Graphene, Strawberry leverages Python's type hints to define schemas, reducing boilerplate and catching errors early.
In this tutorial, you'll learn how to build a production-ready GraphQL API with Strawberry. We'll cover schema design, resolvers, mutations, subscriptions, authentication, and error handling. You'll see real-world patterns like pagination, N+1 query optimization, and integration with FastAPI. By the end, you'll be able to confidently build and debug GraphQL APIs in Python.
Whether you're building a new microservice or adding a GraphQL layer to an existing Django or Flask app, Strawberry provides the tools you need. Let's dive in.
Setting Up Strawberry
First, install Strawberry and an ASGI server like Uvicorn. We'll also install strawberry-graphql-django if using Django, but for this tutorial we'll use FastAPI.
``bash pip install strawberry-graphql fastapi uvicorn ``
Create a file schema.py and define your first type. Strawberry uses Python dataclasses with decorators.
strawberry.Schema(query=Query, mutation=Mutation) to expose your schema. For production, consider using strawberry.tools.create_schema for more control.Resolvers and Field Logic
Resolvers are functions that return data for a field. In Strawberry, you can attach resolvers directly to fields using @strawberry.field. You can also define resolver functions separately.
Let's expand our schema with a resolver that accepts arguments.
strawberry.field(resolver=my_function) to keep types clean. Always validate inputs.Mutations: Changing Data
Mutations are used to modify data. In Strawberry, you define a mutation class with @strawberry.type and mark methods with @strawberry.mutation. Mutations often return a custom response type to include errors.
Let's create a simple mutation to add a book.
Union[Book, AddBookError].@strawberry.mutation and often accept input types. Always return a meaningful response, possibly including error information.Subscriptions: Real-Time Updates
Subscriptions allow clients to receive real-time updates via WebSockets. Strawberry supports subscriptions using async generators. You need an ASGI server that supports WebSockets, like Uvicorn.
Let's create a simple subscription that emits a new book every 5 seconds.
strawberry.channels for Django.@strawberry.subscription and async generators. They require WebSocket support in your server.Integrating with FastAPI
Strawberry provides an integration with FastAPI via strawberry.fastapi.GraphQLRouter. This allows you to add a GraphQL endpoint to your FastAPI app with minimal setup.
Let's create a FastAPI app that serves our schema.
strawberry.extensions for logging and metrics.GraphQLRouter to add a GraphQL endpoint.Authentication and Context
GraphQL APIs often need authentication. Strawberry allows you to pass a context object to resolvers. You can set up authentication in the context and access it in resolvers.
Let's add a simple token-based authentication.
@strawberry.permission classes. They allow you to check permissions before resolver execution.context_getter to inject authentication data into resolvers. Access it via info.context.Error Handling and Unions
GraphQL errors should be communicated clearly. Instead of returning null, use Union types to return either success or error objects. This gives clients structured error information.
Let's create a mutation that can fail.
Error type with a code and message for consistency across your API.The N+1 Query Nightmare
- Always use DataLoader for related fields to avoid N+1 queries.
- Profile your GraphQL resolvers with tools like Apollo Studio or Strawberry's built-in extensions.
- Set query depth and complexity limits to prevent abusive queries.
- Use connection-based pagination (Relay spec) for list fields.
print(result) in resolverstrawberry debug schema| File | Command / Code | Purpose |
|---|---|---|
| schema.py | @strawberry.type | Setting Up Strawberry |
| schema.py | from typing import Optional | Resolvers and Field Logic |
| schema.py | from typing import List | Mutations |
| schema.py | from typing import AsyncGenerator | Subscriptions |
| main.py | from fastapi import FastAPI | Integrating with FastAPI |
| main.py | from fastapi import FastAPI, Request, HTTPException | Authentication and Context |
| schema.py | from typing import Union | Error Handling and Unions |
Key takeaways
Interview Questions on This Topic
What is the N+1 problem in GraphQL and how do you solve it?
Frequently Asked Questions
20+ years shipping production Python across data and backend systems. Drawn from code that ran under real load.
That's Python Libraries. Mark it forged?
3 min read · try the examples if you haven't