how to display enum number instead of enum name in response

Viewed 69

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

3 Answers

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);
}

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 changing from an enum to an Int field.

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

Related