4

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".

9

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.

  • Great minds & all .. You beat me to the answer by 2 minutes. :) – Jules Apr 7 '17 at 17:29
5

At the end of the day, the rules and regulations are there to enforce an idea, which is that any change that is likely to cause clients to break is accompanied by a major version change. This is the core principal behind semantic versioning, and following it in spirit is more important than following the letter of the rules.

So does changing the set of values in your enumerated type break anything? The fact that the values are serialized as strings is irrelevant. Semantically, those strings represent a choice from a restricted set.

Adding a new choice in a document type your API accepts is clearly not going to break anything. No client will generate the new value, but (presumably) nothing requires them to, either.

If your API can generate the value in a response it sends, however, things are different. Existing clients may see values that they don't know how to handle, and are likely to fail. In this case, a major version increase is expected.

A borderline case is if the type is used in responses, but a client can't see the new value unless it uses new features. That could be argued either way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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