Strawberry GraphQL 错误处理完全指南

Strawberry GraphQL 错误处理完全指南

strawberry A GraphQL library for Python that leverages type annotations 🍓 strawberry 项目地址: https://gitcode.com/gh_mirrors/st/strawberry

GraphQL 作为一种强类型查询语言,其错误处理机制与传统 REST API 有着显著不同。本文将深入探讨如何在 Strawberry GraphQL 框架中处理各种类型的错误,帮助开发者构建更健壮的 GraphQL 服务。

一、GraphQL 错误处理概述

在 GraphQL 中,错误主要分为三类:

  1. 查询验证错误(Validation Errors)
  2. 类型系统错误(Type Errors)
  3. 执行时错误(Execution Errors)

与传统 HTTP 错误码不同,GraphQL 总是返回 200 OK 状态码,即使发生错误,也会将错误信息包含在响应体中。这种设计使得客户端能够更灵活地处理部分成功和部分失败的情况。

二、查询验证错误处理

当客户端发送的查询不符合 GraphQL 规范或 Schema 定义时,Strawberry 会在执行前进行验证并返回验证错误。

示例场景

{
  nonExistentField
}

错误响应

{
  "errors": [
    {
      "message": "Cannot query field 'nonExistentField' on type 'Query'.",
      "locations": [{"line": 2, "column": 3}]
    }
  ]
}

特点

  • 验证错误会阻止查询执行
  • 错误信息包含具体位置(行号、列号)
  • 遵循 GraphQL 规范,不可自定义验证规则

三、类型系统错误处理

当解析器返回值与定义的类型不匹配时,Strawberry 会抛出类型错误。

常见情况

  1. 非空字段返回了 None
  2. 返回类型与定义不符

示例代码

@strawberry.type
class Query:
    @strawberry.field
    def required_field() -> str:  # 非空字符串
        return None  # 错误!

错误响应

{
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Query.required_field",
      "path": ["required_field"]
    }
  ]
}

最佳实践

  • 对于可能为空的字段,使用 Optional 类型注解
  • 在解析器内部做好空值检查

四、执行时错误处理

当解析器执行过程中抛出未捕获的异常时,Strawberry 会自动捕获并将其转换为错误响应。

示例代码

@strawberry.type
class Query:
    @strawberry.field
    def user() -> User:
        raise DatabaseError("Connection failed")

响应特点

{
  "data": null,
  "errors": [
    {
      "message": "Connection failed",
      "path": ["user"]
    }
  ]
}

日志记录: Strawberry 默认会将所有执行错误记录到 strawberry.execution 日志器中,便于服务器端排查问题。

五、部分响应与错误混合处理

GraphQL 的一个重要特性是支持部分响应,即当某些字段解析失败时,其他成功解析的字段仍会返回。

示例场景

@strawberry.type
class Query:
    @strawberry.field
    def valid_field() -> str:
        return "Success"
    
    @strawberry.field
    def failing_field() -> str:
        raise Exception("Failed")

响应示例

{
  "data": {
    "valid_field": "Success",
    "failing_field": null
  },
  "errors": [
    {
      "message": "Failed",
      "path": ["failing_field"]
    }
  ]
}

注意事项

  • 只有可选字段(Nullable)才能返回 null
  • 非空字段出错会导致整个父字段变为 null

六、业务错误的最佳实践

对于预期的业务错误,推荐将其建模为 Schema 的一部分,而不是抛出异常。

1. 简单场景:使用 Optional 类型

@strawberry.type
class Query:
    @strawberry.field
    def find_user(id: ID) -> Optional[User]:
        if not user_exists(id):
            return None
        return User(id=id, ...)

2. 复杂场景:使用 Union 类型

对于需要返回详细错误信息的场景,可以使用联合类型:

@strawberry.type
class LoginSuccess:
    user: User
    token: str

@strawberry.type
class InvalidCredentialsError:
    message: str
    remaining_attempts: int

LoginResult = strawberry.union("LoginResult", (LoginSuccess, InvalidCredentialsError))

@strawberry.mutation
def login(username: str, password: str) -> LoginResult:
    if not validate_credentials(username, password):
        return InvalidCredentialsError(
            message="Invalid credentials",
            remaining_attempts=get_remaining_attempts(username)
        )
    return LoginSuccess(user=get_user(username), token=generate_token())

客户端查询示例

mutation Login($username: String!, $password: String!) {
  login(username: $username, password: $password) {
    __typename
    ... on LoginSuccess {
      user { id name }
      token
    }
    ... on InvalidCredentialsError {
      message
      remainingAttempts
    }
  }
}

七、错误处理策略总结

| 错误类型 | 处理方式 | 适用场景 | |---------|---------|---------| | 验证错误 | 自动处理 | 查询语法错误 | | 类型错误 | 类型系统保障 | 返回值类型不匹配 | | 意外错误 | 异常捕获 | 服务器内部错误 | | 业务错误 | Schema 建模 | 预期内的业务规则违反 |

八、高级技巧

  1. 自定义错误格式化:可以继承 Schema 类并重写 process_errors 方法来自定义错误格式

  2. 错误扩展:通过扩展(Extensions)添加额外的错误元数据

  3. 全局错误处理:使用中间件实现统一的错误处理逻辑

class ErrorHandlingMiddleware:
    async def resolve(self, next_, root, info, **args):
        try:
            return await next_(root, info, **args)
        except Exception as e:
            logger.error(f"Error during {info.parent_type.name}.{info.field_name}: {e}")
            raise

schema = strawberry.Schema(..., extensions=[ErrorHandlingMiddleware])

通过合理运用这些错误处理技术,开发者可以构建出既健壮又易于调试的 GraphQL API。记住,良好的错误处理不仅是技术实现,更是 API 设计的重要组成部分。

strawberry A GraphQL library for Python that leverages type annotations 🍓 strawberry 项目地址: https://gitcode.com/gh_mirrors/st/strawberry

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盛丽洁Cub

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值