在 FastAPI 中,不能使用解析器异步等待
in FastAPI, can not use resolver async await
我正在将石墨烯与 fastapi 一起使用,但无法使简单的异步解析器正常工作。感谢您的帮助。
class Query(graphene.ObjectType):
hello = graphene.String(name=graphene.String(default_value=""))
async def resolve_hello(self, info, name):
image_url = "my_url"
async with httpx.AsyncClient() as client:
response = await client.get(image_url)
# img_bytes = await get_bytes(request.query_params["url"])
// do stuff
错误是
{
"data": {
"hello": null
},
"errors": [
{
"message": "There is no current event loop in thread 'ThreadPoolExecutor-1_0'."
}
]
}
TL;DR
将 GraphQL 端点添加到 app
对象时,将其替换为
app = FastAPI()
app.add_route("/", GraphQLApp(schema=graphene.Schema(query=Query),
executor_class=AsyncioExecutor))
完整答案
好的,所以我在检查文档并将它们与您的代码进行比较后发现了您的问题。
这不是 httpx 的问题,而是您如何使用 GraphQL 的问题。
正如您在 Fastapi Docs, the resolve_hello
function is declared with a traditional def
instead of async def
. This makes a difference for the GraphQL engine when running because it calls the function, but does not await it, instead, it gets the coroutine object and goes on with returning the result. Since the result is a coroutine it does not work and throws the exception you posted. The solution lays in the Starlette Docs 中看到的那样,它将 asyncio
引擎作为参数传递给 运行 async
GraphQL 查询。
这很棘手,因为 fastAPI 基于 Starlette,因此您必须阅读这两个文档以备不时之需。
如果问题仍然存在,请告诉我。
因为 Graphene (2) 不再使用 AsyncioExecutor
app = FastAPI()
app.add_route("/", GraphQLApp(schema=graphene.Schema(query=Query),
executor_class=AsyncioExecutor))
我建议使用 Strawbery or starlette-graphene3
如果你想使用 pydantic
pip install starlette-graphene3
如果需要升级你的 pip
import asyncio
import graphene
import pydantic
from fastapi import FastAPI
from starlette.applications import Starlette
from starlette_graphene3 import GraphQLApp, make_graphiql_handler
from graphene_pydantic import PydanticObjectType
class PersonModel(pydantic.BaseModel):
first_name: str
last_name: str
class Person(PydanticObjectType):
class Meta:
model = PersonModel
async def wait_for_me(wo):
return wo
class Query(graphene.ObjectType):
people = graphene.List(Person)
async def resolve_people(root, info):
mmd = await wait_for_me("jose")
return [PersonModel(first_name=mmd, last_name="Smith")]
class Subscription(graphene.ObjectType):
count = graphene.Int(upto=graphene.Int())
async def subscribe_count(root, info, upto=3):
for i in range(upto):
yield i
# await asyncio.sleep(1)
app = FastAPI()
@app.get("/hello")
def read_root():
return {"Hello": "World"}
schema = graphene.Schema(query=Query, subscription=Subscription)
app.mount("/", GraphQLApp(schema, on_get=make_graphiql_handler())) # Graphiql IDE
# app.mount("/", GraphQLApp(schema, on_get=make_playground_handler())) # Playground IDE
# app.mount("/", GraphQLApp(schema)) # no IDE
我正在将石墨烯与 fastapi 一起使用,但无法使简单的异步解析器正常工作。感谢您的帮助。
class Query(graphene.ObjectType):
hello = graphene.String(name=graphene.String(default_value=""))
async def resolve_hello(self, info, name):
image_url = "my_url"
async with httpx.AsyncClient() as client:
response = await client.get(image_url)
# img_bytes = await get_bytes(request.query_params["url"])
// do stuff
错误是
{
"data": {
"hello": null
},
"errors": [
{
"message": "There is no current event loop in thread 'ThreadPoolExecutor-1_0'."
}
]
}
TL;DR
将 GraphQL 端点添加到 app
对象时,将其替换为
app = FastAPI()
app.add_route("/", GraphQLApp(schema=graphene.Schema(query=Query),
executor_class=AsyncioExecutor))
完整答案
好的,所以我在检查文档并将它们与您的代码进行比较后发现了您的问题。
这不是 httpx 的问题,而是您如何使用 GraphQL 的问题。
正如您在 Fastapi Docs, the resolve_hello
function is declared with a traditional def
instead of async def
. This makes a difference for the GraphQL engine when running because it calls the function, but does not await it, instead, it gets the coroutine object and goes on with returning the result. Since the result is a coroutine it does not work and throws the exception you posted. The solution lays in the Starlette Docs 中看到的那样,它将 asyncio
引擎作为参数传递给 运行 async
GraphQL 查询。
这很棘手,因为 fastAPI 基于 Starlette,因此您必须阅读这两个文档以备不时之需。
如果问题仍然存在,请告诉我。
因为 Graphene (2) 不再使用 AsyncioExecutor
app = FastAPI()
app.add_route("/", GraphQLApp(schema=graphene.Schema(query=Query),
executor_class=AsyncioExecutor))
我建议使用 Strawbery or starlette-graphene3 如果你想使用 pydantic
pip install starlette-graphene3
如果需要升级你的 pip
import asyncio
import graphene
import pydantic
from fastapi import FastAPI
from starlette.applications import Starlette
from starlette_graphene3 import GraphQLApp, make_graphiql_handler
from graphene_pydantic import PydanticObjectType
class PersonModel(pydantic.BaseModel):
first_name: str
last_name: str
class Person(PydanticObjectType):
class Meta:
model = PersonModel
async def wait_for_me(wo):
return wo
class Query(graphene.ObjectType):
people = graphene.List(Person)
async def resolve_people(root, info):
mmd = await wait_for_me("jose")
return [PersonModel(first_name=mmd, last_name="Smith")]
class Subscription(graphene.ObjectType):
count = graphene.Int(upto=graphene.Int())
async def subscribe_count(root, info, upto=3):
for i in range(upto):
yield i
# await asyncio.sleep(1)
app = FastAPI()
@app.get("/hello")
def read_root():
return {"Hello": "World"}
schema = graphene.Schema(query=Query, subscription=Subscription)
app.mount("/", GraphQLApp(schema, on_get=make_graphiql_handler())) # Graphiql IDE
# app.mount("/", GraphQLApp(schema, on_get=make_playground_handler())) # Playground IDE
# app.mount("/", GraphQLApp(schema)) # no IDE