GraphQL Python实现:Ariadne/Strawberry原理与对比
请介绍Python中实现GraphQL服务的主要库:Ariadne(Schema-first)和Strawberry(Code-first)的核心用法和设计哲学差异。给出一个简易用户查询的GraphQL Schema定义和Resolver实现。对比REST API与GraphQL在数据获取效率上的区别,以及N+1查询问题在GraphQL中的解决方案(DataLoader)。
回答
孤独的心
Ariadne(Schema-first):先写SDL再绑Resolver。
# schema.graphql
"""
type Query {
user(id: ID!): User
users: [User!]!
}
type User {
id: ID!
name: String!
posts: [Post!]!
}
"""
# resolvers.py
from ariadne import QueryType, gql, make_executable_schema
query = QueryType()
@query.field('user')
def resolve_user(_, info, id):
return db.get_user(id)
schema = make_executable_schema(gql(open('schema.graphql').read()), query)
Strawberry(Code-first):用Python类型定义Schema。
import strawberry
@strawberry.type
class User:
id: strawberry.ID
name: str
@strawberry.type
class Query:
@strawberry.field
def user(self, id: strawberry.ID) -> User:
return db.get_user(id)
schema = strawberry.Schema(query=Query)
REST vs GraphQL:
- REST:多端点,客户端无法精确控制返回字段(over-fetching/under-fetching)
- GraphQL:单端点,客户端指定所需字段,减少网络传输
N+1解决方案(DataLoader):
from ariadne.utils import convert_kwargs_to_snake_case
from promise import Promise
from promise.dataloader import DataLoader
class UserLoader(DataLoader):
def batch_load_fn(self, ids):
users = db.get_users_by_ids(ids)
return Promise.resolve([users.get(id) for id in ids])
@query.field('users')
def resolve_users(_, info):
info.context['user_loader'] = UserLoader()
对比总结:Ariadne适合GraphQL先行的团队;Strawberry适合Pythonic代码优先、类型安全的项目。