Nice seeing you again. I have an issue that I’m trying to solve at work. How do you guys deal with several API versions?
Currently, we use a custom router that redirects the requests to the correct backend - therefore, we have two stacks called green and blue running different versions of our API.
I’m extremely dissatisfied with this setup because we have to deploy 3 times the same project just to update versions - one for the router, one for the green, and another one for the blue. We currently cannot change this setup because oftentimes our deployments have breaking changes from one version to another and we cannot roll out versions as fast as necessary to avoid having multiple versions - we are building a mobile app that takes at least a couple of days to roll out.
This is extremely cumbersome and error-prone, so I wanted to understand how Elixir handles such cases, if at all. This is a major source of issues in our stack and I would love to have a single deployment. My current plan is to absorb all the services into a single stateless monolith - one that I could have the “router”, the various API versions necessary to the current state of the app, horizontal scalability, and a fault-tolerant API - where the parts could fault and the whole would not be at risk.
I hope this is the right place/right way to ask for advice. Any advice, suggestions, critics are welcome and invaluable. Thanks in advance
Not sure I’m reading you well but Elixir is more than well equipped for this. But even without Elixir, what’s the issue in just having HTTP namespaces e.g. /v1 and /v2?
If possible, stop breaking your api. Adopt extend, expand, deprecate. extend calls with non breaking parameters, return values. Expand the api with new calls/paths when extending isn’t possible. deprecation after extension and track use of deprecated calls to ensure client upgrade. using /v1, /v2 works if you want can tolerate entire duplicate routing groups, for massive upgrades when everything goes out the window. but for incremental and higher velocity changes it requires too much house cleaning and setup. an additive mechanism is to version your client’s requests and tune your api to adapt to different client needs. this can get messy and hard to reason about but can help to maintain non breaking changes in limited situations.
Currently, the API is not HTTP, but I get your point. I could change the controller that it uses - which feels a little cumbersome but might be the best solution. I was wondering how would you structure the internals of the API - are v1 and v2 two different gen_servers?
This seems like an architectural design issue to me. What is the reason behind this split, when you could have easily achieved the same with a single codebase?
Here is a context behind why things are the way they are:
The code was acquired from another company that used a proprietary framework they built in-house
Also, the game uses a slight variant of a WebSocket, so that we can offer server pushes to the client - currently used a lot in the game. This router is also the server that the client connects via this WebSocket variation.
Another factor that complicates the matter is that we are in the AppStore and the PlayStore - both of which force us to have at least two different versions of the app live while updating given their multi-day review process. We could remove the router, at a time cost.
We try as much as possible. Unfortunately, sometimes this is not possible. We need to reuse the models we already have and the breaking change is the only way forward.
For instance, we had to change the way missions work in the whole game - before the refactor, they would yield a loot box to be opened after X amount of time; then, it would yield points for the Battle Pass. Duplicating this would be a daunting amount of work and therefore would not be feasible.
Thanks a lot for the link. I’ve read it and the ideas are very interesting indeed. I do need to deep dive into the code to see the step-by-step. There is a major simplifying factor at play: I only need to maintain 2 API versions, because we truly want to pivot the API and only keep the last version for a while.