API Versioning Strategies
APIs evolve over time. Versioning lets you make breaking changes to your API without disrupting existing clients. Choosing the right strategy from day one is critical for long-term maintainability.
1 Versioning Strategies Compared
| Strategy | Example | Pros | Cons |
|---|---|---|---|
| URL Path | /api/v1/users | Simple, visible, easily cacheable | URL changes on upgrade |
| Query Param | /api/users?version=1 | No URL change | Easy to miss, pollutes URLs |
| Header | Accept-Version: 1 | Clean URLs | Less discoverable, harder to test |
| Content Type | Accept: application/vnd.app.v1+json | RFC standard | Complex header management |
Recommendation: Use URL path versioning (/api/v1/) for public APIs — it is the most widely understood and tooling-friendly approach.
2 Implementing URL Versioning in Express
JavaScript — Multi-version Express Router
const express = require("express");
const app = express();
// --- V1 routes ---
const v1Router = express.Router();
const v1Users = require("./routes/v1/users");
const v1Products = require("./routes/v1/products");
v1Router.use("/users", v1Users);
v1Router.use("/products", v1Products);
app.use("/api/v1", v1Router);
// --- V2 routes (breaking changes) ---
const v2Router = express.Router();
const v2Users = require("./routes/v2/users"); // new response shape
v2Router.use("/users", v2Users);
app.use("/api/v2", v2Router);
// --- Version negotiation middleware ---
app.use((req, res, next) => {
const version = req.headers["accept-version"] || "1";
req.apiVersion = parseInt(version);
next();
});
3 Deprecation Notices
JavaScript — Deprecation Header Middleware
// Warn clients they are using a deprecated version
function deprecationWarning(sunsetDate) {
return (req, res, next) => {
res.set("Deprecation", "true");
res.set("Sunset", sunsetDate); // RFC 8594
res.set("Link", '</api/v2/docs>; rel="successor-version"');
next();
};
}
// Apply to all v1 routes
app.use("/api/v1", deprecationWarning("2027-01-01"), v1Router);
4 Code Challenge
Challenge: Refactor an existing Express router to support
v1 and v2. In v2, rename the name field to fullName in user responses. Both versions should work simultaneously without breaking existing v1 clients.