Should your API use enums?

Ted Spence
CodeX
Published in
4 min readMar 20, 2022

Enumerated values are a clever validation technique that can be risky for an API

Enumerated values are a great way to use type safety to your advantage. They make otherwise tricky-to-remember numbers or strings easy to use. Unfortunately they can also pose risks for API developers.

I was a big fan of enums when my team designed the AvaTax REST API; but I’d like to share with you the problems that we faced and why our team has generally reduced our usage of enums when we designed the Lockstep Platform API. Let’s break this down.

Enumerated values can be great building blocks, but they introduce risks for an API (Pixabay)

Using enums as parameters for APIs

Enums work by creating a type-safe mnemonic within your code. Rather than expecting an Integer and hoping that the user will pass in a valid number, you can specify a Season and your code will make more sense.

Consistent use of enum values can make both libraries and APIs easier to use. If you accidentally mistype "Autumn" most editors won’t tell you that you got it wrong; but if you mistype Season.Autumn you’ll get an error, and your code won’t compile.

How did customers know which enums to use? I chose to publish an SDK for each language; I could then define that enum within it. Customers who used the SDK would receive documentation and context-sensitive autocomplete to help them choose the right value for each API call.

On the other hand, customers who use Swagger (aka OpenAPI) specifications directly run two risks. Here’s what the documentation for an enum looks like in Swagger/OpenAPI JSON:

The first problem they face is that the documentation for the meaning of each number doesn’t directly map to each number. The documentation is simply a block of text that the user can read. When you use a swagger interface, your experience looks good but not really optimal:

Some swagger interfaces render enums as a drop-down list box

This is probably manageable, though. But what happens when we ship an update?

Updating your enumerated values

If the customer is using your published SDK, they will automatically see that new value as a choice in the SDK the next time they upgrade. Because enums are represented directly in your editor as autocomplete options, customers will discover that new option either by accident or by reading patch notes.

For customers who chose to write their own code, the results are less than ideal. There is no way for them to know that the new option is available until they read published documentation — but this is probably tolerable, since a customer who writes their own code most likely faces this same problem with every new API you create.

On the other hand, what happens if you use enums in your data models?

Enums and the risk of strict type checking

Most modern languages provide strict type safety. When your API sends back a JSON representation of an object, languages like Java and C# will parse this object using the schema that existed when the object was defined.

If you use enums in your data models, and you expand your enum by adding a new value, anyone who uses the old schema for your model is at risk of a parsing exception. Look at this example code:

This means that customers using version 1.1 of your SDK are at risk of parsing exceptions when you release version 1.2 with a new enum value. Customers with handwritten code may or may not have chosen to use enums and face similar risks.

We can’t prevent all of these risks but we can indeed choose to represent all values in data models as strings or numeric values. We choose to force all these values to be represented as their underlying data types, and we choose to publish our own SDKs, to avoid the risk of forwards incompatible parsing.

Lessons Learned

The goal of backwards compatibility for your API is a neverending challenge. Enums are one small part of the picture, and it’s worth paying attention to them. I strive to reduce the number of instances where we launch an API version with changes that break one customer or another, and the risk of expanding an enum is something we always need to consider.

My conclusion from years of work with APIs and enums is the following:

It’s okay to use an enum as an input parameter to an API request, but enums are dangerous on an output model.

What other tips and techniques have you discovered for backwards compatibility?

Ted Spence teaches at Bellevue College and leads engineering at Lockstep. If you’re interested in software engineering and business analysis, I’d love to hear from you on Twitter or LinkedIn.

--

--

Ted Spence
CodeX
Writer for

Software development management, focusing on analytics and effective programming techniques.