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"
}
]
}