graphql-python / graphene-django

Build powerful, efficient, and flexible GraphQL APIs with seamless Django integration.
http://docs.graphene-python.org/projects/django/en/latest/
MIT License
4.31k stars 770 forks source link

raise GraphQLError inside resolver gives me "Received incompatible instance error" after bumping from 3.0.0b7 to 3.0.0b8 #1367

Closed zhoudaxia233 closed 1 year ago

zhoudaxia233 commented 2 years ago

However, in 3.0.0b7, if I send the same query without logging in, I get "Unauthenticated." (And this is the behavior I expected.)

zhoudaxia233 commented 2 years ago

https://github.com/graphql-python/graphene-django/blob/v3.0.0b8/graphene_django/debug/middleware.py#L69

https://github.com/graphql-python/graphene-django/blob/v3.0.0b7/graphene_django/debug/middleware.py

promise = next(root, info, **args)

has been changed to

try:
    promise = next(root, info, **args)
except Exception as e:
    return context.django_debug.on_resolve_error(e)

I guess this is the reason, but I have no idea how I could achieve the same result with the new version of graphene-django.

pixel8r commented 2 years ago

I'm having the same issue in 3.0.0 (clean install with pip install graphene-django)

test case:

class Query(graphene.ObjectType):
    hello_world = graphene.String()

    def resolve_hello_world(root, info):
        raise GraphQLError("hello error")
        return "hello"

schema = graphene.Schema(query=Query)

query:

{
    helloWorld
}

result (unexpected behavior):

{
  "data": {
    "helloWorld": "<Promise at 0x109c77550 rejected with GraphQLError('hello error')>"
  }
}

result (expected behavior) using same code and query with previous release:

{
  "errors": [
    {
      "message": "hello error",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "helloWorld"
      ]
    }
  ],
  "data": {
    "helloWorld": null
  }
}
zhoudaxia233 commented 2 years ago

@dobsonjon Hi, I found a workaround and maybe this is helpful for you. This issue is caused by their update on the default DjangoDebugMiddleware, however, this is customizable. Here I just copy the old code and create a MyDjangoDebugMiddleware file, then replace the default one with my customized implementation (actually it's their old version implementation) by specifying the path in the GRAPHENE settings.

GRAPHENE = {
    ...
    'MIDDLEWARE': [
        'myproject.middlewares.MyDjangoDebugMiddleware',
    ]
}

Hope this helps.

pixel8r commented 2 years ago

Thanks @zhoudaxia233

Would that affect me even if I'm not using graphene's debug middleware? I have not enabled that feature explicitly anyway. My graphene settings just look like this:

GRAPHENE = {
    "SCHEMA": "helloworld.schema.schema"
}

I do see a difference in this behavior when running on Django's built-in server vs a web server though. When running in my staging environment - (Django + GUnicorn + Caddy2), the errors section of the response appears as expected.

When running locally using Django's development server with DEBUG=False, the errors are also formatted correctly. However, when encountering multiple errors, I only get the first one.

When running locally using Django's development server with DEBUG=True, I get the "<Promise at 0x109c77550 rejected with GraphQLError('hello error')>" response I quoted above.

So it's not unusable, but this difference in behavior makes it very difficult to test effectively.

I'm using Django 3.2.16 if that matters.

pixel8r commented 2 years ago

Ok @zhoudaxia233 I followed your suggestion and defined a custom DjangoDebugMiddleware class with the following change to the original class found in graphene_django.debug.middleware using the suggested edit:

<         try:
<             promise = next(root, info, **args)
<         except Exception as e:
<             return context.django_debug.on_resolve_error(e)
---
>         promise = next(root, info, **args)

and added that to my graphene settings:

GRAPHENE = {
    "SCHEMA": "helloworld.schema.schema",
    "MIDDLEWARE": ['helloworld.schema.DjangoDebugMiddleware']
}

This solved my issues when running in debug mode. Thanks again @zhoudaxia233 for your help with this!

LVladymyr commented 1 year ago

Version: graphene==3.2.1 graphene-django==v3.0.0 still actual.