A question that came up at work recently was, “should we return enums as ints or strings”?
The client-side team shouted that they prefer strings please, rather than “magic” ints.
I’m not a fan of strings, because then the client code becomes tightly coupled to those string values and you’ll see code like this in the clients:
if (customer.type == "goldCustomer") { // do something }
Or, the clients need to have silly display code to make the string enum pretty, like this:
switch (customer.type) { case 'goldCustomer': return 'Gold customer'; case 'silverCustomer': return 'Silver customer'; }
Occasionally these string enums might need to be renamed, e.g.
– one of the values isn’t correct because the business actually calls it something different, so it is confusing.
– there is a typo in the enum string, e.g. “goldCustomre”
But if you’re returning enums as strings, you can’t change any of the values, because renaming the string is a breaking API change which will break all the callers.
A more robust and loosely-coupled approach is to return an object instead, e.g.
"customer": { "type": { "id": 1, "displayName": "Gold customer" } }
The client code then becomes:
if (customer.type.id == 1) { // do something }
Which… I must admit, is a bit sucky and a bit “magic”. Hmm. I need to think about this a bit more…
I suppose the clients could define the enums somewhere in their logic, i.e.
enum CustomerType { Gold = 1, Silver, } if (customer.type.id == CustomerType.Gold) { // do something }
At least, the switch statement in the client code above can be replaced with:
return customer.type.displayName
If the client needs all the values of your enum, e.g. for a select list, it can also be helpful to define the enums in a resource, e.g.
GET /customerTypes, which returns:
{ customerTypes: [ { "id": 1, "displayName": "Gold customer" }, { "id": 2, "displayName": "Silver customer" } ] }