typescriptintermediate

API Versioning Strategy

Implement API versioning with URL path, header-based, and content negotiation strategies.

typescript
import http from 'http';

type Handler = (req: http.IncomingMessage, res: http.ServerResponse) => void;
type VersionedHandlers = Record<string, Handler>;

// Strategy 1: URL path versioning (/v1/users, /v2/users)
function urlVersionRouter(routes: Record<string, VersionedHandlers>): Handler {
  return (req, res) => {
    const url = req.url ?? '/';
    const match = url.match(/^\/v(\d+)(\/.*)/);
    if (!match) { res.writeHead(400); res.end('Missing version'); return; }

    const version = `v${match[1]}`;
    const path = match[2];
    const handler = routes[path]?.[version];

    if (!handler) { res.writeHead(404); res.end('Not found'); return; }
    handler(req, res);
  };
}

// Strategy 2: Header versioning (Accept-Version: 2)
function headerVersionRouter(
  routes: Record<string, VersionedHandlers>,
  defaultVersion = 'v1',
): Handler {
  return (req, res) => {
    const vHeader = req.headers['accept-version'] as string | undefined;
    const version = vHeader ? `v${vHeader}` : defaultVersion;
    const path = req.url ?? '/';
    const handler = routes[path]?.[version];

    if (!handler) {
      res.writeHead(404);
      res.end(JSON.stringify({ error: `${path} not available in ${version}` }));
      return;
    }

    res.setHeader('API-Version', version);
    handler(req, res);
  };
}

// Example handlers
const usersV1: Handler = (_, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify([{ id: 1, name: 'Alice' }]));
};

const usersV2: Handler = (_, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: [{ id: 1, firstName: 'Alice', lastName: 'Smith', email: 'alice@example.com' }],
    meta: { version: 'v2', total: 1 },
  }));
};

// URL versioning server
const routes = { '/users': { v1: usersV1, v2: usersV2 } };
const server = http.createServer(urlVersionRouter(routes));
server.listen(3000, () => console.log('Versioned API on :3000'));
// GET /v1/users → compact response
// GET /v2/users → enriched response

Use Cases

  • API backward compatibility
  • Gradual migration between versions
  • Multi-version REST APIs

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.