微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

FastAPI + GraphQL 在引发异常时出现错误 NoneType 是可调用的

如何解决FastAPI + GraphQL 在引发异常时出现错误 NoneType 是可调用的

我在尝试使用 FastAPI + GraphQL(石墨烯)引发验证错误时卡住了。 我有一个解析器代码

class Query(graphene.ObjectType):  
  list_categories = graphene.List(CategoryGrapheneModel)
  get_category = graphene.Field(CategoryGrapheneModel,id=graphene.Argument(graphene.Int,required=True))

  @staticmethod
  def resolve_list_categories(parent,info):
    return Category.all()

  @staticmethod
  def resolve_get_category(parent,info,id):
    try:
      category = Category.find_or_fail(id)
      return category
    except ModelNotFound as ex:
      raise Exception('Category not found')

但是我没有收到带有消息的 400 HTTP 响应,而是收到 500 Internal Server Error with traceback:

Traceback (most recent call last):
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py",line 394,in run_asgi
    result = await app(self.scope,self.receive,self.send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py",line 45,in __call__
    return await self.app(scope,receive,send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/fastapi/applications.py",line 199,in __call__
    await super().__call__(scope,send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/applications.py",line 111,in __call__
    await self.middleware_stack(scope,send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py",line 181,in __call__
    raise exc from None
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py",line 159,in __call__
    await self.app(scope,_send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/exceptions.py",line 82,in __call__
    raise exc from None
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/exceptions.py",line 71,sender)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/routing.py",line 566,in __call__
    await route.handle(scope,send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/routing.py",line 227,in handle
    await self.app(scope,send)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/graphql.py",line 52,in __call__
    response = await self.handle_graphql(request)
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/graphql.py",line 105,in handle_graphql
    [format_graphql_error(err) for err in result.errors]
  File "/Users/vitalyradchik/Devel/upwork/tipolim/backend/.venv/lib/python3.9/site-packages/starlette/graphql.py",in <listcomp>
    [format_graphql_error(err) for err in result.errors]
TypeError: 'nonetype' object is not callable

谷歌搜索并没有给我一个解决方案。所以请帮忙。

解决方法

处理好了。 问题出在 GraphQLApp 中,调用了未定义的 format_graphql_errors(无)。

为了解决一个问题,我从 GraphQLApp 创建了一个自定义子类,并将 graphql.error.graphql_error 包中的 format_graphql_errors 更改为 format_error。

import json
import typing

from starlette.graphql import GraphQLApp
from starlette import status
from starlette.background import BackgroundTasks
from starlette.concurrency import run_in_threadpool
from starlette.requests import Request
from starlette.responses import HTMLResponse,JSONResponse,PlainTextResponse,Response
from starlette.types import Receive,Scope,Send
from graphql.error.graphql_error import format_error


class CustomGraphQLApp(GraphQLApp):
  async def handle_graphql(self,request: Request) -> Response:
    if request.method in ("GET","HEAD"):
      if "text/html" in request.headers.get("Accept",""):
        if not self.graphiql:
          return PlainTextResponse(
            "Not Found",status_code=status.HTTP_404_NOT_FOUND
          )
        return await self.handle_graphiql(request)

      data = request.query_params  # type: typing.Mapping[str,typing.Any]

    elif request.method == "POST":
      content_type = request.headers.get("Content-Type","")

      if "application/json" in content_type:
        data = await request.json()
      elif "application/graphql" in content_type:
        body = await request.body()
        text = body.decode()
        data = {"query": text}
      elif "query" in request.query_params:
        data = request.query_params
      else:
        return PlainTextResponse(
            "Unsupported Media Type",status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,)

    else:
      return PlainTextResponse(
        "Method Not Allowed",status_code=status.HTTP_405_METHOD_NOT_ALLOWED
      )

    try:
      query = data["query"]
      variables = data.get("variables")
      operation_name = data.get("operationName")
    except KeyError:
      return PlainTextResponse(
        "No GraphQL query found in the request",status_code=status.HTTP_400_BAD_REQUEST,)

    background = BackgroundTasks()
    context = {"request": request,"background": background}

    result = await self.execute(
      query,variables=variables,context=context,operation_name=operation_name
    )
    error_data = (
      [format_error(err) for err in result.errors]
      if result.errors
      else None
    )
    response_data = {"data": result.data}
    if error_data:
      response_data["errors"] = error_data
    status_code = (
      status.HTTP_400_BAD_REQUEST if result.errors else status.HTTP_200_OK
    )

    return JSONResponse(
      response_data,status_code=status_code,background=background
    )

我希望这会对其他人有所帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。