If an API is tightly coupled to its clients (an app and/or SPA for example) or its database, releases often have to be orchestrated carefully in order not to break the application as a whole. Fortunately, there are a few methods to loosen that coupling so all components can be updated independently and more frequently, eliminating the need for big bang releases.
- Add, don't rename or delete
If the API returns JSON, you shouldn't remove or rename properties or endpoints clients depends on. Instead add a new property or endpoint that future client versions will depend on. This way you don't have to wait to release until all clients are updated.
- Only remove features or properties once they're no longer in use
Only remove a property or feature once it is no longer in use to avoid breaking existing versions. With an SPA client this is relatively easy (just wait a few days after releasing the last version), but with an app this is harder. Customers might not always update their apps in a timely manner. Make sure you collect telemetry about usage of features of the app and remove the feature once the usage drops below a certain threshold.
- Encourage client updates
Build new version detection in all clients and encourage the customer to update. This way you won't have to wait too long to remove old features.
- Consider an alternative architecture
Ultimately, if the API could program the client you wouldn't have to worry about introducing breaking changes. The Majestic Monolith is a good example of this, because API and website 'client' are one. Because of that, it's an architecture well worth considering.
If there are SPA and app clients the RESTful SPA can be used. Instead of returning JSON, the API returns rendered HTML. The client doesn't have to know how to interpret the HTML, it just has to present it. The customer and the browser/app will take care of the rest. This way you can introduce new features without even updating the client! The key here is not to hardcode features in the app, but let the API serve them.
- Decouple and version database changes
In order to remain flexible with deploying and rolling back API versions, database changes should be decoupled from API releases. Database changes should be versioned, just like any other component. Make sure the current database version is compatible with the previous, current and next API version, so you are free to deploy and rollback if required.
- Only make backwards compatible database changes
Because the database is versioned separately from the API and deployed while a specific API version is in use, structural changes must always be backwards compatible with the previous, current and next API version. You can still make radical structural changes in the database, you'll just have to chop them into backwards compatible steps.
- Single database access
Ideally, the API should be the funnel for all database access. This way, the API can present a consistent interface even though the database structure changes over time. Reporting tools could operate on the database directly if desired, but some coupling between database and reporting tool must then be accepted.