blb-ventures / strawberry-django-plus

Enhanced Strawberry GraphQL integration with Django
MIT License
179 stars 47 forks source link

Using input_mutation with a None return type throws an exception #256

Open taobojlen opened 1 year ago

taobojlen commented 1 year ago

I have a mutation that looks something like

    @gql.django.input_mutation(permission_classes=[IsAdmin])
    def mutate_thing(
        self,
        info: Info,
    ) -> None:
      # do the thing
      return None

This throws an exception when I try to generate my schema:

  File "/Users/tao/dev/cinder/myapp/mutations.py", line 599, in Mutation
    @gql.django.input_mutation(permission_classes=[IsAdmin])
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/tao/dev/cinder/.venv/lib/python3.11/site-packages/strawberry_django_plus/mutations/fields.py", line 126, in __call__
    types_ = tuple(get_possible_types(annotation.resolve()))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/tao/dev/cinder/.venv/lib/python3.11/site-packages/strawberry_django_plus/utils/inspect.py", line 171, in get_possible_types
    assert_never(gql_type)
  File "/Users/tao/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 2459, in assert_never
    raise AssertionError(f"Expected code to be unreachable, but got: {value}")
AssertionError: Expected code to be unreachable, but got: None

It looks like the issue occurs in get_possible_types, which doesn't handle a None return type. It's possible to work around this by setting the return type annotation to Void._scalar_definition instead of None, but that feels like a hack!

bellini666 commented 1 year ago

Hrm, interesting that setting it to Void fixes the issue.

The main issue here is that input_mutation by default creates a union of its return type with OperationInfo, which will be returned when a django error happens. You can avoid that by passing handle_django_errors=False to the input_mutation

I'm currently merging this lib into strawberry-graphql-django, and in there I'll make that option opt-in instead of opt-out