Microservices: The Static Contract Pitfall and how to avoid it
Tags: microservices, beginners, architecture
Published: 2021-11-30 16:16:16

Hi everyone! I would like to show you how *_The Static Contract pitfall_* could drive APIs to unexpected issues, and how versioning helps to avoid them. For that purpose I will be using *_O'Reilly's Microservices Antipatterns and Pitfalls_* and Microsoft site related to *_RESTful web API design_*. References were added at bottom.

## But what is a pitfall?
According to Richards (2016) a pitfall is 

> something that was never a good idea, even from the start.

And that is the case for *_The Static Contract pitfall_*. This assumption leads APIs to be not flexible enough for contract changes in front of client applications. 

## The Static Contract Pitfall
Imagine having a REST API endpoint consumed by three different client applications, but one of them needs an extension of a service published. So, the API provider in order to deploy the new changes, requires to check compatibility with the others consumers. Ups! Something goes wrong, the changes imply modifying a JSON contract, then consumers will be impacted and none of them would adapt to those modifications at the same time.

![Many clients consume an API endpoint, and changing this service could be complicated](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gltyq1c4uqlkg5ren0io.PNG)

It happens all the time, contracts between providers and consumers are not static. They change very often by adding new features to microservices. However, there are some strategies to keep those issues away and implement backward compatibility without breaking all clients.

## Versioning strategies

### Header versioning
This type of versioning allows to manage the API version by adding the version number in a custom HTTP Header. It requires that client applications use this header to specify which service version will be consumed.
Besides, it is important to consider server-side cache in case every request was stored, here using a proxy could help to reduce duplicated cache data.
In the next example is showed the creation of a new order using an *_api-version_* specified in the *_Custom-Header_*.
```
POST https://enterprise.domain.com/orders/123  
Custom-Header: api-version=1
```

### URI versioning
This technique consist in defining the version of an API in the uniform resource identifier (URI). It makes very clear to know which version will be consumed for client applications. 
For instance, choosing a version of a service used to retrieve an order could be done by *_v1_* or any custom standard. 
It is relevant to mention that this implementation makes harder to follow [HATEOS](https://en.wikipedia.org/wiki/HATEOAS) constraint because all links associated to resources should have defined their correct version number. 
```
GET https://enterprise.domain.com/v1/orders/123  
```

### Query string versioning
Regarding to this versioning strategy, the version goes in the query string parameter. In that case, it is recommended to establish a default version number when a client misses sending this parameter. The following example uses *_?version=3_* as query string. 
```
GET https://enterprise.domain.com/orders/123?version=3
```

As URI strategy, the previous approach has the same issue related to implementation of HATEOS. 

### MediaType versioning
Finally, very closed to header versioning practice, MediaType needs to be sent in the *_Accept Content Type Header_*. Provider is responsible for handling all possible format responses with their defined versions. For example, deleting an order could be performed if version were specified in *_Accept header_* along format response required.
```
DELETE https://enterprise.domain.com/orders/123 
Accept: application/vnd.enterprise.domain.com.v2+json
```

## tl;dr

| Versioning strategy | Location|Some Considerations
| --------- |:---------:| -------:|-------:|
| Header| Custom HTTP header | Server-side cache issues|
| URI| Properly as part of URI |Very simple and clear which version is used<br>Makes harder to implement HATEOAS|
| Query String| Query string param of URI | Should be defined a default version value <br> Makes harder to implement HATEOAS|
| Mediatype| Accept Http header| Handle all possible format responses with their defined versions <br> Server-side cache issues|


## Conclusion
Microservices have became an extended practice in software architecture, from those implementations have emerged many lesson to learn and for this reason there are several antipatterns and pitfalls to take in consideration. Learning from the experience of the others and having in mind those best practices is crucial to build a strong architecture. Here is important to evaluate the options and choose the best one according to context.

##References

Richards, M. (2016). Microservices Antipatterns and Pitfalls. CA: O’Reilly Media.

Microsoft (2021). RESTful web API design. Retrieve from https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design