sparckles / Robyn

Robyn is a Super Fast Async Python Web Framework with a Rust runtime.
https://robyn.tech/
BSD 2-Clause "Simplified" License
3.91k stars 200 forks source link

Strawberry-graphql has a problem with IntrospectionQuery #685

Open mstrumeck opened 8 months ago

mstrumeck commented 8 months ago

Bug Description

Hi! I've decided to use Robyn together with strawberry-graphql but is seems it not working properly. Robyn has a problem with rendering the answer from the standard introspection query. With the following code:

app = robyn.Robyn(__file__)

@app.post("/graphql")
async def handle_api_request(request: robyn.Request) -> robyn.jsonify:
    body = request.json()
    query = body["query"]
    variables = body.get("variables")
    context = {}
    root_value = body.get("root_value", None)
    operation_name = body.get("operation_name", None)
    data = await schema.execute(
        query,
        variables,
        context,
        root_value,
        operation_name,
    )
    return robyn.jsonify({
        "data": (data.data),
        **({"errors": data.errors} if data.errors else {}),
        **({"extensions": data.extensions} if data.extensions else {}),
    })

@app.get("/graphql", const=True)
async def handle_api_playground_request(request: robyn.Request):
    return {
        "description": strawberry.utils.graphiql.get_graphiql_html(),
        "headers": {
            "Content-Type": "text/html"
        }
    }

I going to always get the following response:

ERROR:strawberry.execution:Syntax Error: Unexpected <EOF>.

GraphQL request:1:1869
1 | "\n    query IntrospectionQuery {\n      __schema {\n        \n        queryType
  |  { name }\n        mutationType { name }\n        subscriptionType { name }\n   
  |      types {\n          ...FullType\n        }\n        directives {\n          
  | name\n          description\n          \n          locations\n          args(inc
  | ludeDeprecated: true) {\n            ...InputValue\n          }\n        }\n    
  |   }\n    }\n\n    fragment FullType on __Type {\n      kind\n      name\n      d
  | escription\n      \n      fields(includeDeprecated: true) {\n        name\n     
  |    description\n        args(includeDeprecated: true) {\n          ...InputValue
  | \n        }\n        type {\n          ...TypeRef\n        }\n        isDeprecat
  | ed\n        deprecationReason\n      }\n      inputFields(includeDeprecated: tru
  | e) {\n        ...InputValue\n      }\n      interfaces {\n        ...TypeRef\n  
  |     }\n      enumValues(includeDeprecated: true) {\n        name\n        descri
  | ption\n        isDeprecated\n        deprecationReason\n      }\n      possibleT
  | ypes {\n        ...TypeRef\n      }\n    }\n\n    fragment InputValue on __Input
  | Value {\n      name\n      description\n      type { ...TypeRef }\n      default
  | Value\n      isDeprecated\n      deprecationReason\n    }\n\n    fragment TypeRe
  | f on __Type {\n      kind\n      name\n      ofType {\n        kind\n        nam
  | e\n        ofType {\n          kind\n          name\n          ofType {\n       
  |      kind\n            name\n            ofType {\n              kind\n         
  |      name\n              ofType {\n                kind\n                name\n 
  |                ofType {\n                  kind\n                  name\n       
  |            ofType {\n                    kind\n                    name\n       
  |            }\n                }\n              }\n            }\n          }\n  
  |       }\n      }\n    }\n  "
  |                             ^
ERROR:robyn.server:Error while executing route function for endpoint `/graphql`: 

That's happening always when I trying call http://localhost:8080/graphql with GET

Steps to Reproduce

Your operating system

Linux

Your Python version (python --version)

3.12

Your Robyn version

latest

Additional Info

No response

sansyrox commented 8 months ago

Hey @mstrumeck 👋

Thank you for choosing Robyn 😄 Can you please share your schema class?

patrick91 commented 8 months ago

@sansyrox here's a minimal reproduction:

import robyn

import strawberry

app = robyn.Robyn(__file__)

@strawberry.type
class Query:
    hello: str = strawberry.field(resolver=lambda: "Hello, world!")

schema = strawberry.Schema(query=Query)

@app.post("/graphql")
async def handle_api_request(request: robyn.Request) -> robyn.jsonify:
    import json
    # note this
    body = json.loads(request.body)
    query = str(body["query"])
    variables = body.get("variables")

    data = await schema.execute(
        query,
        variables,
    )

    return robyn.jsonify(
        {
            "data": (data.data),
            **({"errors": data.errors} if data.errors else {}),
            **({"extensions": data.extensions} if data.extensions else {}),
        }
    )

@app.get("/graphql", const=True)
async def handle_api_playground_request(request: robyn.Request):
    from strawberry.http.ides import get_graphql_ide_html

    return {"description": get_graphql_ide_html(graphql_ide="apollo-sandbox"), "headers": {"Content-Type": "text/html"}}

app.start(port=8080, host="0.0.0.0")  # host is optional, defaults to 127.0.0.1

btw using json.loads works, not sure why request.json() doesn't work properly

sansyrox commented 8 months ago

Thanks @patrick91 , but it is still not working for me

image
patrick91 commented 8 months ago

@sansyrox can you show me your cli?

sansyrox commented 8 months ago

@patrick91 , here you go

image