3

I have my (JSON) API structured like this (which I'm pretty happy with):

API Project

/_V1
    /Controllers
        V1EntityController.cs        // Applies to version 1 only
/_V2
    /Controllers      
        V2OtherEntityController.cs   // Applies to versions 2 and below
/Controllers/
    EntityController.cs              // Applies to versions 2 and above
    OtherEntityController.cs         // Applies to versions 3 and above

Core Project

/Data/Entity.cs
/Data/OtherEntity.cs

But as the project has progressed both the Entity and OtherEntity classes has become full of legacy properties and a bunch of ShouldSerializexxx methods. They also then also contain properties and sub-classes which are only for serialization.

Would a better solution for this be to create "Models" in the API project like so:

API Project

/_V1
    /Controllers
        V1EntityController.cs
    /Models
        V1EntityModel.cs
/_V2
    /Controllers      
        V2OtherEntityController.cs
    /Models
        V2OtherEntityModel.cs
/Controllers
    EntityController.cs
    OtherEntityController.cs
/Models
    EntityModel.cs
    OtherEntityModel.cs

Then convert to and from the classes in the core project? What's the industry recognised practice for handling this scenario?

  • Do you need to host multiple versions of the same controller or model simultaneously? Otherwise I'm not really seeing the point of this explicit versioning. Better to use semantic versioning on the entire API, and if you need to make breaking changes, then make them all at once and increment the major version number so everyone knows what you did. – Aaronaught Jan 7 '14 at 22:13
  • In short, yes! The controllers were just examples, in the actual app they are much more complex - not simple CRUD controllers - so the way they handle data has changed in the major versions. – Jamie Jan 8 '14 at 7:46
  • I understand that there have been/will be significant changes, but is there some reason you actually need to have the older version running in parallel? Typically, backward-compatible changes don't require you to run multiple versions, the new version simply tolerates data in the old format; and non-backward-compatible changes (i.e. those that would imply incrementing the major version) render the old version completely unusable. What domain or business requirement demands that you be able to run both concurrently? – Aaronaught Jan 8 '14 at 23:10
  • @Aaronaught, in some settings, you might be constrained to support several versions of a client in parallel. For instance, a large percentage of your customers might still be using an app which consumes your api, running on android 2.4. You can't force upgrade them to the new mobile app because their phone may not support it. The concern is completely legit. – Sinaesthetic Jan 29 '14 at 3:17
2

My vote is on trying to avoid such scenarios. Normally, I don't care when I add new members to a class, because most consumer don't care about newly appearing stuff either. But of course, removing members is a breaking change, but these things happen all the time, you just have to communicate it. I would say breaking changes are the industry standard, it's just cheaper, and doesn't end up with messy code.

My favorite solution is in WCF, see for example here: http://msdn.microsoft.com/en-us/library/ms733832%28v=vs.110%29.aspx. Basically, when you add a new property to your data class, the clients won't bother at all, and you'll even get that data back in a round-trip, thanks to the IExtensibleDataObject infrastructure.

If you really have to support different data class versions at the same time, then I would try to separate the classes, one new class for each new version. I would use interfaces, inheritance, view-models for different versions, or even tools like AutoMapper to decrease the amount of copy-pasted code.

| improve this answer | |
1

I've tried a couple different approaches: version the entire project into it's own namespace (e.g. v1-controllers, models, etc) or just version what you need (e.g. v3 controller uses v2 operation which uses v1 repositories, etc). Depending on the complexity of the software, each has it's own pros and cons. We had gotten to a point where only versioning what you need to version will eventually get unmanageable. For instance, if you use generic interfaces, you will inevitably encounter the situation where versioning something that implements that interface will force you to version everything else down the chain which is no bueno. If you did a good job separating client contracts from domain objects and database entities, then you should be a bit better off because you're really just mapping your client contracts back to your domain object, and since the domain object shouldn't really need to be versioned all that often (almost never, really), you should be pretty safe. There are other several patterns that can help you sort of "shuttle" out the correct versions as the path is executing.

The short solution might be to version the whole chain, depending on how often you release. Your project can get pretty large if you release a lot, and fixing a bug in one version wont fix it in the others, so there will be a lot of extra work. But, in the end, it's easier to manage as a whole since it becomes a [safe] free-for-all when the entire chain is versioned. And since being forced to support many versions is lame anyway, having multiple copies doesn't seem quite AS lame.

| improve this answer | |

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.