100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js & Express Backend
25 minintermediate

API Versioning Strategies

API Versioning Strategies

API versioning lets you evolve your backend without breaking existing clients. When you change a response shape, rename a field, or deprecate an endpoint, older clients should continue to work until they migrate. Express supports multiple versioning strategies — URI path versioning, query parameter versioning, header versioning, and Accept-header (media type) versioning — each with different trade-offs in visibility, cacheability, and client ergonomics.

Analogy🏏Cricket
Think of it like cricket: The ICC's different tournament formats each have a distinct identity: Test matches are five days, ODIs are fifty overs, T20s are twenty overs. Nobody is confused about which format they are watching because the format is explicitly declared in the event name. URL path versioning follows the same principle: /api/v1/players and /api/v2/players are unambiguously different contracts, and every developer, log file, monitoring dashboard, and caching layer can distinguish them without needing to inspect headers or query strings. Just as the ICC does not hide the format in a metadata field that only sophisticated score-tracking apps can read, you should not hide your API version in a header that only sophisticated HTTP clients can specify. The insight is that explicitness in versioning reduces integration errors, and URL path versioning is the most explicit mechanism available.

URI Path Versioning

The most common strategy: embed the version in the URL path, e.g., /api/v1/users and /api/v2/users. Clients know exactly which version they are calling, URLs are bookmarkable and cache-friendly, and server logs make version usage immediately visible. The downside is that URIs should ideally identify resources, not API contracts, but this pragmatic trade-off is widely accepted.

javascript
// Route-level URI versioning
const v1Router = require('./routes/v1');
const v2Router = require('./routes/v2');

app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);

// routes/v1/users.js
router.get('/users', (req, res) => {
  res.json({ users: getUsersV1() }); // flat array
});

// routes/v2/users.js
router.get('/users', (req, res) => {
  res.json({                         // paginated envelope
    data: getUsersV2(),
    meta: { page: 1, total: 200 }
  });
});
Analogy🏏Cricket
Think of it like cricket: Each edition of the IPL has its own rulebook and auction system. IPL 2023 teams operated under 2023 rules; IPL 2024 brought new Impact Player rules. Both editions' data coexist in the record books with their year clearly in the label. URI versioning does the same — the year (version) is stamped right in the address.

Header and Query Parameter Versioning

Header versioning uses a custom request header such as X-API-Version: 2 or Accept: application/vnd.myapp.v2+json. Query parameter versioning appends ?version=2 to the URL. Both keep the canonical resource URL clean but are less visible in browser address bars and harder to test without tools like curl or Postman.

javascript
// Header-based versioning middleware
function versionMiddleware(req, res, next) {
  const version = req.headers['x-api-version'] || '1';
  req.apiVersion = parseInt(version, 10);
  next();
}

app.use(versionMiddleware);

app.get('/api/users', (req, res) => {
  if (req.apiVersion >= 2) {
    return res.json({ data: getUsersV2(), meta: {} });
  }
  res.json(getUsersV1());
});

// Query parameter versioning
app.get('/api/users', (req, res) => {
  const v = parseInt(req.query.version || '1', 10);
  res.json(v >= 2 ? { data: getUsersV2() } : getUsersV1());
});
Analogy🏏Cricket
Think of it like cricket: Some international venues have a 'premium gate' entry. Your ticket (header or query param) gets checked at the door; the gate itself doesn't change, but what you see inside depends on which ticket tier you hold. The stadium address stays the same; only your access level differs.
Lesson 17 of 36
0% complete