API versioning allows you to evolve your APIs while maintaining existing client integrations. It's a simple but powerful way to introduce changes, add features, or even phase out old functionality while keeping everything running smoothly. In this tutorial, you'll learn how to implement API versioning in Express.js with practical examples.



Understanding API Versioning

APIs are constantly changing to stay relevant and useful. With versioning, you can update functionality or introduce new features without disrupting existing API users. It keeps older integrations running while offering newer clients access to advanced features.

Why Use API Versioning?

  • Backward Compatibility: Existing users continue to use the older version while new features are added in updated versions.
  • Flexibility: Developers can experiment and refine features without disrupting client applications.
  • Clarity: Both API providers and consumers understand the supported versions.

Popular Strategies for API Versioning

Let's break down three common ways to handle API versioning:

URI Versioning

Here, you add the version number directly into the URL. This is simple and easy to understand:

GET /api/v1/users
GET /api/v2/users

Header Versioning

The API version is passed in a custom header. This keeps the URL clean:

GET /api/users
Header: X-API-Version: 1

Query Parameter Versioning

The version is included as a query parameter:

GET /api/users?version=1

Implementing URL-Based Versioning in Express.js

Here's an example that demonstrates versioning by defining distinct routes for each version in the URI:

// server.js
const express = require('express');
const app = express();

// Middleware to parse JSON
app.use(express.json());

// API v1
app.get('/api/v1/users', (req, res) => {
    res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Neha' }]);
});

// API v2
app.get('/api/v2/users', (req, res) => {
    res.json([{ id: 1, fullName: 'Alice Smith' }, { id: 2, fullName: 'Neha Johnson' }]);
});

app.listen(3000, () => console.log('Server is running on port 3000'));

Header-Based Versioning in Express.js

Header-based versioning leverages custom headers to specify the API version:

// server.js
const express = require('express');
const app = express();

// Middleware to parse JSON
app.use(express.json());

// Middleware to check version
app.use('/api/users', (req, res, next) => {
    const version = req.headers['x-api-version'];
    if (!version) {
        return res.status(400).send('API version header is required');
    }
    req.version = version;
    next();
});

// API versioning logic
app.get('/api/users', (req, res) => {
    if (req.version === '1') {
        res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Neha' }]);
    } else if (req.version === '2') {
        res.json([{ id: 1, fullName: 'Alice Smith' }, { id: 2, fullName: 'Neha Johnson' }]);
    } else {
        res.status(400).send('Unsupported API version');
    }
});

app.listen(3000, () => console.log('Server is running on port 3000'));

Query Parameter Versioning in Express.js

Query parameter versioning involves appending the version to the query string:

// server.js
const express = require('express');
const app = express();

// Middleware to parse JSON
app.use(express.json());

// API with query parameter versioning
app.get('/api/users', (req, res) => {
    const version = req.query.version;
    if (!version) {
        return res.status(400).send('Version query parameter is required');
    }

    if (version === '1') {
        res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Neha' }]);
    } else if (version === '2') {
        res.json([{ id: 1, fullName: 'Alice Smith' }, { id: 2, fullName: 'Neha Johnson' }]);
    } else {
        res.status(400).send('Unsupported API version');
    }
});

app.listen(3000, () => console.log('Server is running on port 3000'));

Version Deprecation

When it's time to retire an older version, do it thoughtfully:

  1. Notify Clients: Let users know about the changes via documentation, emails, or even headers.
  2. Set a Timeline: Set a clear deadline for when the old version will stop working.
  3. Log Usage: Use analytics to see who's still using the deprecated version.

Deprecation Header Example

Use deprecation headers to warn users about deprecated APIs:

app.use('/api/v1/', (req, res, next) => {
    res.set('Warning', '199 - "API v1 is deprecated and will be removed by [date]"');
    next();
});

Conclusion

This tutorial taught you that API versioning is critical for evolving APIs while maintaining backward compatibility. You explored three key strategies—URI, header, and query parameter versioning—along with practical implementations in Express.js. Additionally, you discovered how to deprecate older versions gracefully, ensuring a seamless transition for users. These techniques help you manage API updates effectively without disrupting existing integrations.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram