API Versioning

You need a version the day you must change a response in a way that breaks a client you do not control. Adding a field is not that day — a client reading data.title is unaffected by a new data.isbn, which is why "additive changes are free" is the first rule of API evolution. Renaming year to publishedYear or removing a field breaks someone, whatever the release notes say.

Four ways to version an HTTP API
Scheme Looks like Strength Weakness
URI path /api/v2/books Visible and cacheable Two URLs per resource
Custom header X-API-Version: 2 Clean URLs Needs Vary; invisible
Media type ...bookshelf.v2+json Purist HTTP Poor tooling
Query parameter /api/books?v=2 Easy to add later Mixes view and identity

Pick the path. The header and media-type schemes are more faithful to HTTP, but /api/v1 is greppable, works in a browser address bar, needs no Vary header to stay cacheable, and mounts as one line of Express 24,430 . Version the major number only — /api/v1.2 means clients pin to a patch level and you can never ship one. Routers are the right unit: app.use('/api/v1', v1Router) beside app.use('/api/v2', v2Router), with store, validation and business rules in one place. Here v2 renames one field and nests another while v1 answers as it always did:

Output of 61
> GET /api/v2/books/bk_012
< 200 OK
{"data":{"id":"bk_012","title":"The Hobbit","publishedYear":1937,
         "author":{"name":"J. R. R. Tolkien"},"genre":"fantasy","rating":4.7}}
> GET /api/v1/books/bk_012?fields=id,title,year
< 200 OK
{"data":{"id":"bk_012","title":"The Hobbit","year":1937}}

A version needs a retirement plan or you will run five forever, and the sunset date belongs in the protocol as well as the changelog: Deprecation (RFC 9745) and Sunset (RFC 8594) are standard headers a client's monitoring can alert on.

Telling clients a version is going awayCSS
v1.use((req, res, next) => {
  res.set('Deprecation', '@1780272000');        // 1 Jun 2026, a Date structured field
  res.set('Sunset', 'Wed, 30 Jun 2027 23:59:59 GMT');
  res.set('Link', '<https://docs.example.com/api/v2-migration>; rel="deprecation"');
  next();
});

Then measure: log the version on every request (Correlation IDs) and you can answer the only question that matters at sunset, which is which API keys still call v1 and how often.