Semantic Versioning in OpenAPI with Enum Strings

enumopenapisemantic-versioning

My team is preparing to add new capabilities to an OpenAPI contract and our implementation of it. There are pre-existing clients. We are planning to take our API from v1.1 to v1.2 while fully respecting semantic versioning.

Our team is debating whether we must go to v2.0 instead of v1.2 if we add new possible values to a type definition like this (in yaml):

Thing:
  type: object
  properties:
    field:
      type: string
      enum:
        - PreExistingValue1
        - PreExistingValue2
        - NewValue1
        - NewValue2

With NewValue1 and NewValue2 being newly introduced possibilities in v1.2. The v1.1 API does not have these two values in the enum.

EDIT: Our Thing is only used in the response data.

Basically my question is, is it OK to do this with a minor version increase, or must we bump up the major version number to change the API in this way?

I'll try not to reveal which side of this argument I'm on and represent the for/against arguments as neutrally as I can:

  • Arguing for only a minor version increase, one team member stated that ultimately, this field is a string, and that isn't changing, so it is OK for this string to take on new values and that is not a threat to backwards compatibility. It is reasonable to expect a client to ignore a string value it does not understand in this field.
  • Arguing for only a minor version increase, one team member stated that the OpenAPI enum is "just documentation", that fundamentally we are only declaring a string field in the contract, nothing more.
  • Arguing for a major version increase, one team member stated that because the contract defines it as an enum, the contract in effect carries a guarantee that the string will only have certain values; and with this change that guarantee is now broken. Depending on choice of serialization framework in the client implementation, data using the new values may actually be rejected within framework code automatically.

To me, this difference of opinion within the team seems to boil down to the question of how "strong" the enum concept is in OpenAPI – whether it is to be considered as part of the type definition or, as the one team member said, "just documentation".

Within the specification, enum refers to this IETF spec which states of enum instances:

An instance validates successfully against this keyword if its value is equal to one of the elements in this keyword's array value.

But the specification does not say "if and only if". It just says "if".

Best Answer

It's my understanding that you have to increment the major version number if your code introduces breaking changes.

If Thing is used strictly for input and you're now accepting a couple of new values, then you won't break any existing code.

However, if you're returning Thing and I have code like

switch (myThing) {
    case PreExistingValue1:
        doProcess1(myThing);
        break;
    case PreExistingValue2:
        doSomethingElse();
        break;
    default:
        throw new NotImplementedException();
}

returning new values will break my code. That's something I'd like to know about.

Related Topic