API Primer — Versioning APIs

Prashant Prasannakumaran
3 min readJul 25, 2021

Welcome to the second set of in depth details about the art of building APIs

Here’s a link to the first part related to API Naming Conventions

If these are useful or need improvement or you find something which does not look right, please do share your valuable feedback.

A live project is constantly evolving with new functionality being added daily resulting in constant changes at the API layer

The below aspects of an API can change over time

  • Path parameter
  • Query parameter
  • Headers
  • Payload: Request/Response
  • Database schema changes
  • Change in business logic like new integration or new validations
  • External dependencies (APIs, etc.) change
  • Endpoint to be changed (extremely rare)

Why versioning

  • Time to integrate

External consumers of your API need time to adapt to the changes

  • Deployment dependencies

Even if your APIs are used within your team and you can coordinate releases of say UI and API, deployment delays between microservices, high availability, etc. mean that we have to support backward compatibility in most cases

Approaches

Database

Here’s a ready reckoner

Maintainable database changes

Code

  • Feature Flags

Passed via environment variables to the application to enable / disable functionality as needed. Much needed when all features / changes are pushed to master

  • New versions via version in the path parameter — “v1”, “v2” so on

Here’s a Decision Matrix that will be helpful

Impact on application code

Typically, application code consists of following packages

  • com.company.api.v1.controller
  • com.company.api.v1.dto
  • com.company.api.v1.dto.mapper [ DTO to Model mapping. Idea being service layer only deals with Models ]
  • com.company.api.v1.dto.validator [ input sanitization and validation ]
  • com.company.service [ business rules/validations and persistence logic ]
  • com.company.dao
  • com.company.model

Now let’s break up the changes to try and decipher how to walk the talk i.e. code

For any changes to Path/Query Parameters, Headers and Request/Response Payloads it’s best to add new packages per version

  • com.company.api.v[n].controller
  • com.company.api.v[n].dto
  • com.company.api.v[n].dto.mapper
  • com.company.api.v1.dto.validator

If these changes trigger changes into model, then we can choose to manage models

  • add to current model
  • extend current model for the next version
  • create a new package and model

For changes to business logic, depending on the change we can

  • add to same function: especially applicable if we have feature flag protected changes
  • create a new function in same Service class
  • create a new package/class to map to v2 packages in other layers

Overall, its best to create separate packages while minimizing code duplication and maximizing code reuse.

Clean up

Ensure that old un-used code from past versions are periodically cleaned up to avoid lots of unused code flows.

Conclusion

Hope the details were helpful and meaningful to help you derive a strategy that works for your projects.

--

--