1

I am building a SDK that will simplify the use of my API.

The problem is if when I have to return property of type enum. For example, I use strings instead of int for displaying enum such as

{
  "type": "CAR"
}

instead of

{
"type": 1
}

Now, my question regarding SDK design/development is should I parse this "type" property as enum or as string? If I parse it as enum, I am always in a danger that if new enum value is added, this conversion will throw an error. If I tend to anticipate it, and catch that error, I am still ending up with either a caught exception or invalid enum value.

On the other hand if I return it as string this problem is gone, but I am expecting that client (client app) keeps track of all the enums and enum changes.

What would be an expected approach? or if there is another way to handle this, please suggest.

John
  • 773
  • 2
  • 7
  • 19
  • Of all the ways C# is a wonderful language, its version of ENUM is pretty annoying, to me at least. – Graham May 04 '20 at 14:49

1 Answers1

3

If I parse it as enum, I am always in a danger that if new enum value is added, this conversion will throw an error.

An error being thrown when the code can't handle the current situation is desirable. Failing in silence is the source of bugs, it's not the solution.

What you're implying is that you can fix your engine by turning off the "check engine" light. It doesn't solve the problem, it hides it, and that's going to bite you in the long run.

I am building a SDK that will simplify the use of my API.

The SDK is presumably going to handle the connection to the API, but it's not going to alter the data that comes from the API, I would assume. If not, I highly suggest reconsidering what exactly you expect your SDK to do, and question why that same behavior isn't already being exposed by your API as well.

Ideally, your SDK simply returns the code-consumer-friendly equivalent of whatever your API is already returning. Therefore, the API and SDK should be reusing the same enum. This specifically prevents the API from having enum values that the SDK doesn't, or vice versa.

Personally, I let my API and SDK depend on the same contract (= separate project which contains the enums, DTOs, ...) and have them be published at the same time. This ensures that each new version of the API comes with its own version of the SDK, thus ensuring that they are in sync with one another. Any consumer who wishes to target a specific version of the API can simply find the SDK with the matching version number.

Now, my question regarding SDK design/development is should I parse this "type" property as enum or as string?

Why is your API exposing an enum to its consumers if you are now going to question whether your SDK should be exposing an enum to its consumers? That makes little sense. The SDK should mirror the API for its data contract. If the SDK shouldn't expose an enum, neither should the API.

  • Do your consumers care that this is an enum?
  • Are they expected to handle this enum or know the closed list of values that it contains?
  • Is this enum going to be used by the consumer to pass to the SDK/API?

If you answered "yes" to any of these, then you're probably going to want to expose the enum itself.

Whether you use an enum or a string depends on how you intend to handle it:

  • Integer values are easy to handle, but lower on the human-readability scale.
  • Strings are harder to handle but are more human-readable.

This is a decision you have to make: is the effort to parse strings worth having a more human-readable API?

If the SDK is the only intended consumer of the API, then you can just have the API return the integer value. If you wish for humans to be able to use your API directly (even if only developers who are debugging it), it may be worth converting the enum value to a string for readability's sake.

We can't make this decision for you. How you design your data contract is up to you. Use whatever makes the most sense for your use case. Whether you prioritize the SDK's concerns or the SDK consumer's concerns is at your discretion.

Flater
  • 44,596
  • 8
  • 88
  • 122
  • I appreciate your time to make such an elaborate answer, but you responded by adding more question that were really not addressing my concerns here. Basically the main focus of my question is the best way for SDK to handle future enum values. Of course SDK will catch the exception, but I dont think my SDK would have to throw an exception that would break client app just because type VAN is added. I tend to believe that is more natural that SDK returns VAN or CAR as string, and let client app handles these value according to client app needs. – John May 04 '20 at 14:11
  • In this case enums should be well documented, because as you mentioned there is no way for client to know what values to expect. – John May 04 '20 at 14:12
  • @John: If you've already decided how the SDK should return its data, then why post the question? The questions I asked in this answer are to urge to you properly analyze your needs so you can find the solution that fits instead of making a big picture guess. Either option is possible, but you haven't explored your use case deeply enough to know which option you should favor. And if you've already decided, as your first comment here concludes with, then the question itself is moot. – Flater May 04 '20 at 14:15
  • @John: _"I dont think my SDK would have to throw an exception that would break client app just because type VAN is added"_ It's better to fail than to return bad data and act like it's good (or to task your consumers with writing their own custom validation to cover for our SDK's known failures). You're right that it's better to not fail at all, and the enum going out of sync can be avoided as I've already addressed in the answer. My point in the first paragraph of the answer is that silent failures are not an improvement over loud failures if it's still the same thing failing. – Flater May 04 '20 at 14:16
  • Actually at this moment my SDK returns enums instead of strings and the problems behind it are terrible. Expecting a client to update SDK (lets say nuget package) because I have added additional value is beyond crazy. I am learning from my mistakes, and I find this approach very problematic. Of course, I dont want to run into a new approach that would have a new set of issues. I am just making a point that it is more natural for client to expect values, rather then SDK to enforce them. After all client app is using SDK, not other way arround. Furthermore, if I introduce a new enum value.... – John May 04 '20 at 14:35
  • ... client will not discover it by itself. So documentation is always a starting point, either that or client has to manually play with enum values. So either way initiative will come from client.. Breaking client code with SDK throwing exception for every new value seems odd. – John May 04 '20 at 14:36
  • @John _"Expecting a client to update SDK (lets say nuget package) because I have added additional value is beyond crazy."_ I'd say the craziness starts with trying to write an SDK that will remain compatible with all future versions of your API. _"I dont want to run into a new approach that would have a new set of issues."_ Every approach has its own set of issues. Otherwise, there'd have to be a universally perfect approach, and then everyone would already be using it. – Flater May 04 '20 at 14:40
  • @John: Your comments suggest that there is an underlying misunderstanding on the expectations/interaction between an API, SDK and the SDK's consumer; which are the driving force behind some of the assertions you're making about what's bad and what's good. I disagree with the underlying premise, but this can't be discussed in scope of the concrete question you've posted here. I suggest you analyze your situation and expected use case more deeply so you're able to make an informed decision on the approach that fits your situation best - but keep in mind that every approach has its drawbacks. – Flater May 04 '20 at 14:43
  • *I'd say the craziness starts with trying to write an SDK that will remain compatible with all future versions of your API.* So you are suggesting that adding a new enum value to one of its existing properties, while remaining the same response class should be a new API version? That is a lot of API versions to consider. In a real world scenario it would imply creating new enum type in order to prevent exposing new enum value to old API versions. Your idea sounds nice, but I am not sure how much good would that bring in practice – John May 04 '20 at 14:58
  • Having enum as request parameter sounds great and easy to maintain, but enum as response parameter/property not so great. – John May 04 '20 at 15:00
  • @John (1) An enum is part of the contract. If the enum changes, so does the contract. If the contract changes, a new version of the API should be released. If a new version of the API is released, a new version of the SDK should be released (2) How often are you changing your enum? It seems like you're using an enum as a dynamically growing data set, which is not what enums should be used for. (3) If a DTO class changes between versions, you'd have two separate DTO classes (one for each version). Why would it be strange to do the same when your enum changes between versions? – Flater May 04 '20 at 15:02
  • It all depends how mature you API is. Early stage API tends to have more frequent changes. Maybe I am not following REST design guidelines to the letter, but I am not doing /v11/vehicles because I have added a new property to the contract. I tend to version API only if breaking changes occur (https://tyk.io/when-and-how-do-you-version-your-api/) – John May 04 '20 at 15:18
  • @John: If you need a data set that can dynamically grow without requiring a new version to be deployed, then an enum is simply not applicable to your use case (in your codebase itself, *let alone* a public API or SDK), rendering the question as posted moot. – Flater May 04 '20 at 15:20
  • This conversation would be much more productive if you would not assuming a lot of things all the time. But again, thanks for the input as it is. – John May 04 '20 at 15:25
  • @John: I've repeatedly suggested deeper analysis specifically so neither of us has to make assumptions. Regardless, your description of how you want this closed list of values to be able to grow without requiring a rebuild of your application (and thus a new version) is directly opposed with how an enum works, since an enum is **fixed** after it has been compiled. You're using the wrong tool to solve the problem. – Flater May 04 '20 at 15:27
  • I can agree that changing an Enum should be considered as a breaking change, but like I mentioned, early stage of API tend to have a lot of changes not necessarily requiring them to dynamically grow. Typo or a domain shaping mistake could lead to change of enum. Me being in that position requires flexibility and that is why I am leaning towards string instead of enums. After reaching a API stability, and maybe for major update for V2, use of enums and versioning on each breaking change would make more sense. – John May 04 '20 at 15:40
  • *You're using the wrong tool to solve the problem* I dont really understand this statement – John May 04 '20 at 15:47
  • @John: You're expecting contradictory things. Your consumers always depend on your interface. Whenever your interface changes, so must your consumers. However, you're balking at the idea of having to update your consumers whenever your interface changes, while at the same time stating that quick small changes are initially unavoidable. **So don't have consumers on a volatile interface then**. If you don't want to update your consumers for changes made when the platform is still unstable, don't release the SDK to consumers until the platform is sufficiently stable as per your expectation. – Flater May 04 '20 at 16:28
  • @John: There's a circular pattern here. Whenever you get presented with an concrete answer, you counter with a completely different choice and imply it's the route you've decided to take. What exactly are you hoping to achieve with your question? Because it seems like your mind is made up about how to approach things. I'm no longer responding to further comments, the question has been repeatedly answered and the goalposts keep shifting. – Flater May 04 '20 at 16:32
  • Again, a totally wrong assumption. A good advice I can take from this discussion is enum change IS a breaking change and should act accordingly. – John May 04 '20 at 16:36