Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Best practices for business versioning within Web APIs
Context
Our team is developing a solution mainly composed of several microservices relying on ASP.NET Core.
We have decided that the simplest and most cost-effective solution would be for services to support multiple versions at the same time at pod level (the same application might expose multiple versions at the same time as opposed to running different pods for different versions).
We have also decided to avoid function-level versioning logic (i.e. if statements checking for something related to a specific version), so that it is easy to phase out an older version once no client uses it.
We expect a maximum of three versions at the same time.
While controller-level versioning (API versioning) is covered in numerous articles, I cannot find many details about how to version the underlying services.
Let's consider a simple example:
-
POST /v1/messages
callsMessageService
which in turn relies on a validator (MessageApiModelValidator
) to validate the input - a
MessageMapper
translates theMessageApiModel
toMessage
(the EF model) - a repository (
MessageRepository
) is called to persist the message
Let's consider a breaking change at the MessageApiModel
level (e.g. a new mandatory property is added). This means that MessageApiModel, MessageMapper and possibly MessageService will be versioned.
Option 1 - keep the class names
We have also aligned to keep the older versions in special folders. The structure would look like this:
Messages
│
├── _versions
├──── v1
├────── Mappers
├──────── MessageMapper.cs
├────── Models
├──────── MessageApiModel.cs
├────── Services
├──────── MessageService.cs
├────── Validators
├──────── MessageApiModelValidator.cs
├── Mappers
├──── MessageMapper.cs
├── Models
├──── MessageApiModel.cs
├── Services
├──── MessageService.cs
├── Validators
├──── MessageApiModelValidator.cs
The breaking changes are implemented directly in the "normal" folder structure (outside of the _versions folder) and the older versions include a clone of the existing affected files (only the changes files are cloned).
- the main pro I see is that we keep the class names clean.
- the main con I see is that by having the same class name, one needs to be very careful to reference the correct class. This is especially important due to the auto-import feature of Visual Studio (might pick the wrong version and not realize it).
Option 2 - apply explicit versioning on class names
In this case the folder structure is almost identical, but all affected class names get the version as a suffix:
Messages
│
├── _versions
├──── v1
├────── Mappers
├──────── MessageMapperV1.cs
├────── Models
├──────── MessageApiModelV1.cs
├────── Services
├──────── MessageServiceV1.cs
├────── Validators
├──────── MessageApiModelValidatorV1.cs
├── Mappers
├──── MessageMapper.cs
├── Models
├──── MessageApiModel.cs
├── Services
├──── MessageService.cs
├── Validators
├──── MessageApiModelValidator.cs
The main pro I see is that when working with an instance it is very clear which version is used. Also, there is no need for namespace disambiguation (namespace alias).
The main con I see is that the class names look strange and somewhat redundant (the namespace already includes the version).
Regardless of the option, phasing out a version means removing the folder(s) for that version and fixing a few compilation errors (e.g. service registration).
What are the best practices surrounding business class versioning for breaking changes that affect multiple classes?
0 comment threads