ADR: OSDU API Versioning Strategy.
ADR: OSDU API Versioning Strategy.
Status
-
Proposed -
Trialing -
Under review -
Approved -
Retired
Context
-
We have mature APIs solidified through time, but they are not immutable for life. From time to time, changes are suggested, for example, osdu/platform/system/partition#49
-
OSDU Java-based services communicate through interfaces defined in the Core-Common library, those interfaces must be aligned with related service API, for example https://community.opengroup.org/osdu/platform/system/lib/core/os-core-common/-/tree/master/src/main/java/org/opengroup/osdu/core/common/storage?ref_type=heads
-
This ADR mainly refers to cases when we have the necessity to change existing concepts. We are suggesting the introduction of a way to handle those changes, keeping compatibility, and minimizing configurations.
Problem Statement
- We do not have a strategy to introduce breaking changes in APIs without disrupting existing environments or making overcomplicated configurations.
- Any change requires updates in Core-Common interfaces and in services that rely on those APIs, slowing down development time. Change should be adopted from top to bottom, from service that provides API to services that consume it.
- It's impossible to support two versions at a time, change should be implemented everywhere. Major changes are happening with the same interfaces, we're not introducing them as new entities but doing a rewrite of existing logic.
Proposal
- Introduce API-compatible autodiscovery configurations in Core-Common. Using Spring Conditions we can introduce self-assembling configurations, enabling compatible clients in an automated manner.
- Improve /info endpoint response by providing services API version in it.
Decision
- Add the supported API version to the /info endpoint response:
{
"groupId": "org.opengroup.osdu",
"artifactId": "partition-gc",
"version": "0.26.0-SNAPSHOT",
"api-version": "V2"
.....
}
- Introduce autodiscovery mechanism to Core-Common, client configurations that would pick implementations according to a response from /info endpoints.
- If API changes require updates in consumer service, introduce them not as a replacement for current functionality but as an addition, relying on autoconfigures from Core-Common.
Pros:
- Reduced configuration hell, no need to point out each API version manually in the environment or properties.
- Defined versioning strategy.
- Ability to introduce new API versions, keeping existing environments intact.
Cons:
- Bean configs that depend on HTTP requests to fetch API version could slow down initial service initialization.
Pseudocode example:
@ConditionalOn(PartitionAPICondition.class)
public class PartitionServiceV1{
V1 compatible logic...
}
@ConditionalOn(PartitionAPICondition.class)
public class PartitionServiceV2{
V2 compatible logic...
}
public class PartitionAPICondition{
getApiVersion(){
String apiVersion = partition.getApiVersion()
return apiVersion;
}
}
Use cases
We do not need this approach if:
- OSDU API change does not require changes in existing logic.
- If a new API introduces new entities, and new endpoints, and can be handled by corresponding service without changes in their clients.
- If new APIs are complementary to existing ones.
For example, Storage Replay API osdu/platform/system/storage#187 doesn't require changing existing Reindex API in Indexer, it adds new entities and will be handled separately.
This approach might help us if:
- OSDU API change requires changes in existing services client, logic, data structure, and the way they communicate.
- If API change affects existing entities that are widely used within service logic.
To keep backward compatibility we usually can put the required changes in place. Update the client or add a new one. The main purpose of this ADR is to simplify the maintenance of those changes. Instead of configuring each component manually, pointing out what components should be present in the operating platform, rely on auto configurations via discovery.
Rationale
- With a versioning strategy that offers backward compatibility development process can go faster.
- Existing environments, that are bound to stable APIs wouldn't block Platform evolution.
- Defining a standard way of versioning APIs will improve Platform maintenance, and help to unify configurations that are currently a mixture of env variables, properties, etc.
Consequences
- Adding API version to the /info endpoint.
- Changes in Core-Common, the introduction of API version self-discovery mechanism.
- Requirement to follow new versioning approach.
Alternatives
Similar approach but without autodiscovery:
@ConditionalOn(PartitionAPIV1Property)
public class PartitionServiceV1{
V1 compatible logic...
}
@ConditionalOnProperty(PartitionAPIV2Property)
public class PartitionServiceV2{
V2 compatible logic...
}
public class PartitionAPICondition{
PartitionAPIV1Property = false;
PartitionAPIV2Property = true;
}
}
Pros:
- no impact on initialization time
Cons:
- It could be a configuration hell, configuring all API versions through properties
partition.api=v2
storage.api=v1
entitlements.api=v3
etc, etc.
Keep things as they are:
- The proposed solution might be overcomplicated, and violate the YAGNI principle, if use cases are limited, then we can define strategy per change, instead of introducing a standard.