MIT License

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

用类型注解重写 GraphQL:Strawberry 的工程取舍

项目背景与痛点

Python 生态里 GraphQL 的早期答案基本是 Graphene:schema 与业务模型两套表述,字段靠 graphene.String()、graphene.List() 手工拼装,resolver 挂在字段上。代价显而易见——改一个字段要动两处,而 mypy、pyright 对此一无所知。Ariadne 走了另一条路:schema-first,先写 SDL 再绑 resolver,schema 可读性好了,但类型一致性只能等到运行时才暴露,IDE 补全和 CI 静态检查形同虚设。

Strawberry 的定位很明确:让 Python 的类型注解成为 schema 的唯一真相来源。你写的是普通的 dataclass 风格类,装饰器把它翻译成 GraphQL 类型。这本质上是一次元编程赌注——把 GraphQL 的类型系统映射到 typing 体系上,Optional[str] 对应 nullable String,list[User] 对应 [User!]!。一旦这套映射成立,mypy 就成了 schema 的第一道编译器检查。

核心技术揭秘

整体链路可以概括为:类定义 → 注解反射 → 内部类型对象 → Schema 组装 → graphql-core 执行。

graph TD A[类定义与类型注解] --> B[反射解析 get_type_hints] B --> C{"存在循环引用?"} C -->|"是"| D[LazyType 延迟求值] C -->|"否"| E[映射为 GraphQL 类型] D --> E E --> F[Schema 组装] F --> G[graphql-core 执行引擎] G --> H[Resolver 分发] H --> I[SchemaExtension 钩子] I --> J[序列化返回]

几个关键设计点值得展开。

注解反射是真正的核心引擎。 Strawberry 重度依赖 typing.get_type_hints 与 inspect,把 Annotated、Union、Optional、泛型、NewType 归一化成内部的 StrawberryType。难点在于 Python 的表达力远超 GraphQL——TypedDict、Protocol、协变泛型在 GraphQL 里无处安放,所以它必须做严格的子集收敛,遇到不支持的注解直接报错,而不是悄悄降级成 Any。这种"宁可失败也不猜测"的取向,比很多自动推导 schema 的方案可靠得多。

LazyType 解决循环引用。 两个类型互相引用时,注解求值会陷入死循环。Strawberry 用字符串形式的延迟引用把解析拆成两阶段:先收集所有类型,再统一链接。这是 schema 构建里最容易被低估的一环。

Resolver 的三态处理。 字段可以没有 resolver(直接取属性)、可以是同步函数、也可以是 async 函数。框架在构建期就完成归类,执行时按需 await,避免"全异步"带来的无谓开销。Info 对象把 context、root、field_nodes 打包传入,横切逻辑有了落脚点。

扩展而非中间件链。 SchemaExtension 提供请求开始、字段解析、请求结束三个钩子,权限(permission_classes)、日志、复杂度限制都走这一层。相比把中间件塞进每个 resolver,扩展是 schema 级别的横切,职责更干净。

功能亮点与差异

相较于 Graphene,Strawberry 的杀手锏是"零重复":一个类既是业务模型又是 GraphQL 类型。相较于 Ariadne,它赢在静态可分析——类型错误在 CI 阶段暴露,而不是等生产环境的第一个查询把问题打出来。

被低估的是 Federation 支持。@strawberry.federation.type(keys=["id"]) 配合 resolve_reference,让 Python 服务能直接接入 Apollo 超级图,对把单体拆成多个 GraphQL 子图的团队,迁移成本远低于重写 schema。

另一个实用细节是 schema_converter:它能读入 Graphene 的 schema 反向生成 Strawberry 类型。迁移路径是设计过的,不是让你推倒重来。

应用场景与落地建议

适合的场景:已有强类型领域模型的 Python 后端、用 FastAPI 或 Django 需要暴露 GraphQL 的服务、多团队共享 schema 的联邦架构。

落地时这几点绕不开:

  • N+1 必须自己治。 用 DataLoader 做批量加载,别指望框架自动解决关联查询。
  • 权限别只挂在 Query 根上。 扩展是 schema 级的,字段级鉴权需要显式配置。
  • 加深度与复杂度限制。 Strawberry 不内置,得自己写 extension,这是上线前的必选项。
  • 把 schema 变更当 API 契约管理。 类型注解改起来太容易,恰恰更容易破坏兼容性,建议在 CI 里做 schema diff 门禁。
  • 异步驱动要选对。 默认执行器是同步的,异步 resolver 需要对应的视图适配层。

综合评价

优点:把 Python 类型系统用到了极致,schema 与代码同构,静态检查友好;扩展模型设计克制,没有过度抽象;Federation 和迁移工具说明作者理解真实生产环境。

缺点:类型注解的表达力天花板就是它的天花板,复杂泛型或动态 schema 需求会很快撞墙;文档偏示例化,extension 生命周期这类深层机制资料不足;社区体量远小于 Graphene,老牌 Django 生态的第三方集成往往需要自己补。

一句话:团队已经在用 mypy 约束类型,Strawberry 是 Python 生态里最自然的选择;如果还在 schema-first 和 code-first 之间摇摆,先想清楚你的类型真相究竟在哪一边。

关于

GitHub 原始描述(英文)

A GraphQL library for Python that leverages type annotations 🍓

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
6129
价值分
3027
活跃状态
活跃

语言占比

CSS
Dockerfile
HTML
JavaScript
Python
Shell
TypeScript

Release

README

Strawberry GraphQL

Python GraphQL library based on dataclasses

Discord PyPI

Installation ( Quick Start )

The quick start method provides a server and CLI to get going quickly. Install with:

pip install "strawberry-graphql[cli]"

Getting Started

Create a file called app.py with the following code:

import strawberry


@strawberry.type
class User:
    name: str
    age: int


@strawberry.type
class Query:
    @strawberry.field
    def user(self) -> User:
        return User(name="Patrick", age=100)


schema = strawberry.Schema(query=Query)

This will create a GraphQL schema defining a User type and a single query field user that will return a hardcoded user.

To serve the schema using the dev server run the following command:

strawberry dev app

Open the dev server by clicking on the following link: http://0.0.0.0:8000/graphql

This will open GraphiQL where you can test the API.

Type-checking

Strawberry comes with a mypy plugin that enables statically type-checking your GraphQL schema. To enable it, add the following lines to your mypy.ini configuration:

[mypy]
plugins = strawberry.ext.mypy_plugin

Django Integration

A Django view is provided for adding a GraphQL endpoint to your application.

  1. Add the app to your INSTALLED_APPS.
INSTALLED_APPS = [
    ...,  # your other apps
    "strawberry.django",
]
  1. Add the view to your urls.py file.
from strawberry.django.views import GraphQLView
from .schema import schema

urlpatterns = [
    ...,
    path("graphql", GraphQLView.as_view(schema=schema)),
]

Examples

Contributing

We use uv to manage dependencies, to get started follow these steps:

git clone https://github.com/strawberry-graphql/strawberry
cd strawberry
uv sync
uv run pytest

For all further detail, check out the Contributing Page

Pre commit

We have a configuration for pre-commit, to add the hook run the following command:

pre-commit install

Licensing

The code in this project is licensed under MIT license. See LICENSE for more information.

Recent Activity

评论

暂无评论