Skip to content

[BUG] GraphQL Uses Enum Case Names Instead of Backing Values, Breaking Filters #6996

Open
@lcottingham

Description

@lcottingham

API Platform version(s) affected: 4.x

Description
When using backed enums with API Platform's GraphQL integration, there's a disconnect between how Doctrine persists the enum (using the backing value) and how the GraphQL schema represents the enum (using the case name).

This creates issues when filtering with backed enums, as the values expected by GraphQL queries don't match what's stored in the database.

How to reproduce

  1. Create a PHP backed enum:
enum CategoryTypeEnum: string
{
    case MAIN_TYPE = "category.main_type";
    case SUB_TYPE = "category.sub_type";
    case OTHER_TYPE = "category.other_type";
}
  1. Use this enum in an API Platform resource and database entity
#[ORM\Column(length: 255, enumType: CategoryTypeEnum::class)]
private ?CategoryTypeEnum $category = null;
  1. Check the GraphQL schema introspection, which shows:
{
    "kind": "ENUM",
    "name": "CategoryTypeEnum",
    "enumValues": [
        {
            "name": "MAIN_TYPE",
            "description": null
        },
        {
            "name": "SUB_TYPE",
            "description": null
        },
        {
            "name": "OTHER_TYPE",
            "description": null
        }
    ]
}
  1. When attempting to filter using these enum values in GraphQL, the filter fails because it expects the backing value but receives the case name.

Looking at the GraphQL\Type\Definition\EnumType object:

GraphQL\Type\Definition\EnumType Object
(
    [config] => Array
        (
            [name] => CategoryTypeEnum
            [values] => Array
                (
                    [MAIN_TYPE] => Array
                        (
                            [value] => MAIN_TYPE  // Should be "category.main_type"
                        )
                    [SUB_TYPE] => Array
                        (
                            [value] => SUB_TYPE  // Should be "category.sub_type"
                        )
                    [OTHER_TYPE] => Array
                        (
                            [value] => OTHER_TYPE  // Should be "category.other_type"
                        )
                )
        )
)

The issue is that while FieldsBuilder::getEnumFields() correctly retrieves backing values with $rCase->getBackingValue(), somehow these values are being replaced with case names in the final EnumType object.

Possible Solution
One of two approaches could be taken:

  1. The GraphQL schema should use the backing values as enum values, matching how they're stored in the database
  2. Or, API Platform could provide a configuration option to choose between using case names or backing values for GraphQL enum representations

This would ensure consistency with Doctrine's behavior, where backed enums are persisted using their backing values.

Additional Context
The backed enum filter fails because it uses tryFrom() with the value from GraphQL, which doesn't match the backing value:

private function resolveEnum(string $resourceClass, string|int $id): ?\BackedEnum
{
    // ...
    $enum = $resourceClass::tryFrom($id); // Fails when $id is "MAIN_TYPE" instead of "category.main_type"
    // ...
    return $enum;
}

It's important to note that this appears to be a disconnect created from the webonyx/graphql-php package integration. REST endpoints resolve correctly with the proper enum backing values, and the issue is only created once we pass the enum config into the webonyx's EnumType() class. The problem seems to occur at this boundary between API Platform and the underlying GraphQL library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions