6

Imagine there is an endpoint GET /v1/status which returns one of predefined statuses that are documented. For example one of [disabled, enabled]. The endpoint can be used by other third party services.

The problem that I see with just adding a blocked status as is, is that third party clients will not be able to process this case or even can have something like:

if (status == 'disabled') {
  // do something when status disabled
} else {
  // do something when status enabled
}

Bumping a version an maintaining 2 versions does not seem like a good solution for such a small change.

What is the best approach to add a new status, for example blocked, without breaking third party clients that might depend on this endpoint? Or what is a better way to design or document public API to avoid such problems in future?

3
  • 1
    Enums in REST are dangerous, because you may or may not want existing clients to treat future enum values the same as current ones and they have no way to design for that ahead of time.
    – Jack
    Nov 14, 2017 at 20:06
  • 2
    A rule of thumb for enums I saw in another question's answers is "an enum is for when you can list all possible values that will ever exist" like days in a week. Nov 14, 2017 at 22:19
  • 1
    Why not add an "undefined" status at the start of the design, to shield you from the future changes? That way, any newly added status should be treated as "undefined" until clients learn how to use it. Sep 14, 2018 at 6:12

2 Answers 2

5

Changing what an endpoint returns by extending the enumeration it returns is not a backwards compatible change. (On the other hand, extending an enumeration that is provided to an endpoint is.)

This suggests two possible solutions to the problem you're in now (besides increasing the version number): 1) don't extend the enumeration but pass additional information some other way, or 2) use a new endpoint. Both of these approaches assume that the new information isn't necessary to use the interface in old ways. But of course this is just what backwards compatibility is. The first approach might take the form of returning a "reason" from the status endpoint via the body, headers, or possible the HTTP status code. The latter would be a new endpoint, statusDetails say, that could return the "reason" described in the previous approach. Indeed, this second approach is just the first approach but using a new endpoint to provide the information. I'm guessing, but I suspect there isn't a big difference between "blocked" and "disabled" to a program consuming the API, and the difference between the two is just a matter of why it's not enabled. In other words, if a consumer just treated "blocked" as "disabled" it would still function correctly.

If my guess is correct, then the original design seems perfectly reasonable, and it's the new approach that is unreasonable (besides being backwards incompatible). The new approach sounds like changing booleans to True, False, FileNotFound. If my guess is incorrect, the it's hard to say what's reasonable without knowing the intent of the endpoint. For example, if it was intended to be just "informational", then an open data type like a string should have been used with very weak guarantees given in the documentation to discourage misuse. Alternatively, if it's more like the state of a state machine, then, at the very least, different naming should have been used and adding a new state to the state machine would very much be a backward incompatible change and not "small" at all. This would be a very unusual design choice for a REST API though.

1
  • or 2) use a new endpoint – nah, adding a new attribute and marking the old enum-based attribute as deprecated would suffice. No need for a new endpoint.
    – observer
    Oct 26, 2021 at 18:22
1

The way I would avoid it on the client side is to explicitly list the combinations in my if statement and fail if it isn’t there much in the style of Dykstra’s Guarded Command Language GCL

Though that is my habit and not necessarily what others would do.

That being said you are making an API change that is not backwards compatible in all situations as such a version bump is needed or an addendum to the contract for the current version is provided.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.