DEV Community

Cover image for Microservices: The Static Contract Pitfall and how to avoid it
Allan B/H
Allan B/H

Posted on • Updated on

Microservices: The Static Contract Pitfall and how to avoid it

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

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
Enter fullscreen mode Exit fullscreen mode

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 constraint because all links associated to resources should have defined their correct version number.

GET https://enterprise.domain.com/v1/orders/123  
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Makes harder to implement HATEOAS
Query String Query string param of URI Should be defined a default version value
Makes harder to implement HATEOAS
Mediatype Accept Http header Handle all possible format responses with their defined versions
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

Discussion (0)