-
-
Notifications
You must be signed in to change notification settings - Fork 146
Description
Feature Request Type
- Core functionality
- Alteration (enhancement/optimization) of existing feature(s)
- New behavior
Description
When returning an interface from a mutation like so -
@strawberry.type
class ProjectsMutation:
"""A collection of project-related GraphQL mutations."""
update_external_project: ExternalProject = mutations.update_external_project(
description="Updates an external project."
)
# ...
# NB: The below mutations act on the `Project` interface. Since the mutations already return a union
# with `OperationInfo`, and interfaces are prohibited in unions, we must expand the full `Project` type.
update_project: Project = mutations.update_project(
description="Updates a generic project."
)
# ...This raises an error that Interfaces cannot form part of a union.
https://spec.graphql.org/September2025/#sec-Unions.Type-Validation
"The member types of a Union type must all be Object base types; Scalar, Interface and Union types must not be > member types of a Union. Similarly, wrapping types must not be member types of a Union."
I can see that the union.types both Project | OperationInfo, but since Project is an interface, this assertion fails.
Workaround
Explicitly type the mutation with concrete types rather than interface, e.g.
update_project: WebProject | ExternalProject | ... = mutations.update_project(
description="Updates a generic project."
)Solution
Detect when an interface is being unioned with the OperationInfo here:
strawberry-django/strawberry_django/mutations/fields.py
Lines 143 to 155 in 4c7a47d
| types_ = tuple(get_possible_types(resolved)) | |
| if OperationInfo not in types_: | |
| types_ = functools.reduce(operator.__or__, (*types_, OperationInfo)) | |
| name = capitalize_first(to_camel_case(self.python_name)) | |
| resolved = Annotated[ | |
| types_, | |
| strawberry.union(f"{name}Payload"), | |
| ] | |
| self.type_annotation = StrawberryAnnotation( | |
| resolved, | |
| namespace=getattr(self.type_annotation, "namespace", None), | |
| ) |
And automatically spread any Interfaces in types_.
tl;dr - replace interface Project with its concrete types, e.g. WebProject | ExternalProject | ... | OperationInfo.