用 FastAPI 与 Strawberry 构建 GraphQL 服务
FastAPI + Strawberry GraphQL 实战:类型注解定义 Schema、查询实现、Mutation 数据修改,打造类型安全、支持显式 Schema 演进的现代 API。
直接回答:FastAPI 与 Strawberry GraphQL 是天作之合:两者都以 Python 类型注解为核心,Schema 定义就像写 dataclass 一样自然;组合起来得到高性能、类型安全、自动文档的 GraphQL 服务,兼容性仍需通过字段弃用策略和契约测试维护。
为什么这对组合
Strawberry 把 GraphQL Schema 写成带类型注解的 Python 类——与 FastAPI/Pydantic 的心智模型完全一致,需学习 GraphQL 类型、解析器和权限模型;FastAPI 提供 ASGI 高性能底座与依赖注入。两者相加,是 Python ASGI GraphQL 的一种组合。
搭建服务
pip install "fastapi[standard]" "strawberry-graphql[fastapi]"
# main.py
import strawberry
from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter
@strawberry.type
class Book:
id: int
title: str
price: float
BOOKS = [Book(id=1, title="深入理解 Python", price=99.0)]
@strawberry.type
class Query:
@strawberry.field
def books(self) -> list[Book]:
return BOOKS
schema = strawberry.Schema(query=Query)
app = FastAPI()
app.include_router(GraphQLRouter(schema), prefix="/graphql")
uvicorn main:app 启动,访问 /graphql 自带 GraphiQL IDE,立即查询:
query { books { title price } }
Schema 设计的要点
类型即文档:每个 @strawberry.type 自动进入 Schema,字段类型注解就是 GraphQL 类型。可选字段用 str | None,列表用 list[X]——Python 类型系统的表达力直接映射到 GraphQL。
Resolver 里的数据获取:
@strawberry.type
class Query:
@strawberry.field
async def book(self, id: int) -> Book | None:
# 项目实现:按所用驱动的参数占位语法执行参数化查询
row = await repository.get_book(id)
return Book(**row) if row else None
Strawberry 的同步 resolver 也运行在事件循环中,不像 FastAPI 同步路由自动进入线程池;同步阻塞 IO 需显式卸载,异步 IO 应 await。
Mutation:数据修改
@strawberry.type
class Mutation:
@strawberry.mutation
def create_book(self, title: str, price: float) -> Book:
book = Book(id=len(BOOKS) + 1, title=title, price=price)
BOOKS.append(book)
return book
schema = strawberry.Schema(query=Query, mutation=Mutation)
mutation { createBook(title: "GraphQL 实战", price: 79.0) { id } }
Mutation 示例仅用于本地内存演示,需把最终 schema 定义移到 GraphQLRouter 构造之前,已创建的 router 不会跟随变量重新赋值。生产应改为带认证、对象级权限和输入校验的事务写入;BOOKS 不持久化且不支持多进程一致性。复杂输入用 @strawberry.input。
生产清单
- N+1 防护:嵌套 resolver 配 Strawberry 的 DataLoader 集成批量加载;
- 深度/复杂度限制:
strawberry的查询分析扩展挡住恶意嵌套; - 鉴权:FastAPI 依赖注入进 GraphQL 上下文(
context_getter),resolver 里读当前用户; - 订阅(Subscription):Strawberry 支持 WebSocket 订阅,实时场景直接可用。
常见问题(FAQ)
Q:Strawberry 和 Graphene 怎么选?
A:Strawberry 类型注解风格现代、异步友好,与 FastAPI 同气质;Graphene 老成,Django 集成深。FastAPI 项目可优先评估 Strawberry 的官方集成。
Q:GraphQL 适合所有 API 吗?
A:不。对外公开给不熟悉合作方的简单 API、文件上传下载、Webhook——REST 更直白。GraphQL 的甜区是"前端需求多变、数据关系复杂、多端消费"。
Q:怎么做接口版本管理?
A:GraphQL 哲学是"演进而非版本":字段只加不删,废弃用 @deprecated 标记。这正是它相对 REST v1/v2 的核心优势。
官方参考
本文基于官方文档整理,未进行运行时或性能测试。示例中的业务函数、数据模型和部署地址需结合项目补全;局部片段不等同于完整生产应用。