1

When trying to get an answer using hotchocolate, in fields with enum type the answer is in the form of a string, and I need an enum value

[UseProjection]
    public IQueryable<Cart> GetActualCart([Service] ApplicationDbContext context, ClaimsPrincipal claimsPrincipal, int pageNumber = 1, int pageSize = 10)
    {
        var userId = claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier);
        return context.Carts
            .Where(f => f.CourierId == new Guid(userId))
            .FromPage(pageNumber, pageSize);
    }

public class Cart : AuditableBaseEntity<Guid>
{
    public Guid CourierId { get; set; }
    public CartStatus Status { get; set; } = CartStatus.Building;
    public virtual ICollection<CartItem> Items { get; set; } = new HashSet<CartItem>();
}

public enum CartStatus
{
    Building = 1,
    WarehouseDelivery = 2,
    WarehouseRefund = 3, 
    CartRefund = 4, 
}

RESPONSE:

"data": {
"actualCart": [
  {
    "courierId": "efb60c9e-c6fe-4479-bd93-82fb23ad63b5",
    "status": "BUILDING"
  },
  {
    "courierId": "efb60c9e-c6fe-4479-bd93-82fb23ad63b5",
    "status": "WAREHOUSE_DELIVERY"
  }
]

Console Image of Query and Response

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
  • Why do you want this? In the generated schema you've specified that `Status` is an enum and those are its values. Clients understand this already - the clients are supposed to respect the published schema. – Panagiotis Kanavos Sep 08 '22 at 14:01
  • Unless you ensure the GraphQL schema to say that `Status` is *not* an enum, all valid clients will be broken – Panagiotis Kanavos Sep 08 '22 at 14:02

3 Answers3

2

If it is acceptable that the Cart.status field is of type Int instead of being an enum type, you can bind the CartStatus to the IntType and use a converter:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddGraphQLServer()
        .BindRuntimeType<CartStatus, IntType>()
        .AddTypeConverter<CartStatus, int>(source => (int) source);
}
paolo
  • 2,528
  • 3
  • 17
  • 25
1

A GraphQL enum will always yield the name as a response. Infact the GraphQL enum element name cannot start with a number.

https://spec.graphql.org/October2021/#sec-Enum-Value

The name specification is here: https://spec.graphql.org/October2021/#Name

0

First of all, consumers of your API should not care for the numeric enum value. If they do it's a clear sign that your abstraction is leaking and your consumers are depending on an implementation detail of your API.

That being said, as Michael already mentioned there is no spec compliant way to return a number literal as an enum value. You could work around this, but then your server would no longer be spec compliant, which will introduce a whole new suit of issues for you.

The simplest way to solve your problem would be to just swap your enum for the Int scalar:

builder.Services
    .AddGraphQLServer()
    // Each occurence of the CartStatus should be represented as Int
    .BindRuntimeType<CartStatus, IntType>()
    // How to convert a CartStatus to the integer value (output)
    .AddTypeConverter<CartStatus, int>(source => (int)source)
    // How to convert an int to the CartStatus enum value (input)
    .AddTypeConverter<int, CartStatus>(source => (CartStatus)source);

If you REALLY need the number value, but you also want to keep the enum for discoverability's sake, you could create a wrapper type that returns both the enum value and the number value. Assuming your enum is named Status you can create a wrapper object like the following:

builder.Services
    .AddGraphQLServer()
    .BindRuntimeType<Status, StatusObjectType>();
 
public class StatusObjectType : ObjectType
{
    protected override void Configure(IObjectTypeDescriptor descriptor)
    {
        descriptor.Name("StatusObject");
 
        descriptor.Field("value")
            .Type<EnumType<Status>>()
            .Resolve(context => context.Parent<Status>());
 
        descriptor.Field("code")
            .Resolve(context => (int)context.Parent<Status>());
     }
 }

For every resolver that returns the Status enum it will automatically map to this wrapper object.

A consumer would then be able to query your enum field like this:

Example call

Tobias Tengler
  • 6,848
  • 4
  • 20
  • 34