Skip to content

Versioning Rest

DodaTech 2 min read

title: "Versioning REST APIs — Practical Versioning Strategies for REST" description: "Versioning REST APIs requires choosing between URI, header, or content negotiation strategies while maintaining RESTful principles and HATEOAS compatibility." date: 2026-06-28 lastmod: 2026-06-28 weight: 23 tags: [apis, versioning] }

Versioning REST APIs involves choosing a strategy (URI, header, or content negotiation) that balances RESTful purity with practical client needs and infrastructure constraints.

What You'll Learn

  • REST-specific versioning considerations
  • HATEOAS and versioning
  • Hypermedia links across versions

Why It Matters

REST APIs have unique versioning challenges around hypermedia links, resource identifiers, and statelessness that other API styles don't face.

REST Versioning Implementation

# RESTful versioning with HATEOAS support
from flask import Flask, jsonify, request
from werkzeug.routing import Rule

app = Flask(__name__)

class RESTVersioning:
    """Versioning middleware that supports HATEOAS links."""

    @staticmethod
    def resource_url(endpoint, version, **kwargs):
        """Generate versioned resource URLs."""
        return f"/v{version}/{endpoint.format(**kwargs)}"

    @staticmethod
    def add_version_links(response, version, resource_id):
        """Add HATEOAS links with versioned URLs."""
        response['_links'] = {
            'self': RESTVersioning.resource_url('users', version, id=resource_id),
            'collection': RESTVersioning.resource_url('users', version),
            'next': RESTVersioning.resource_url('users', version, page=2)
        }
        return response

# v1 endpoint
@app.route('/v1/users/<int:id>')
def get_user_v1(id):
    user = find_user(id)
    response = user.to_v1_dict()
    return jsonify(RESTVersioning.add_version_links(response, 1, id))

# v2 endpoint
@app.route('/v2/users/<int:id>')
def get_user_v2(id):
    user = find_user(id)
    response = user.to_v2_dict()
    return jsonify(RESTVersioning.add_version_links(response, 2, id))
// Express REST versioning with hypermedia
function versionedRouter(basePath, version, handlers) {
  const router = express.Router();

  Object.entries(handlers).forEach(([method, handler]) => {
    router[method](basePath, (req, res) => {
      const result = handler(req);
      result._links = {
        self: `/v${version}${req.path}`,
        version: `/v${version}`,
        docs: `/docs/v${version}`
      };
      res.json(result);
    });
  });

  return router;
}

const v1 = versionedRouter('/users', 1, {
  get: (req) => users.map(u => ({ id: u.id, name: u.name }))
});

const v2 = versionedRouter('/users', 2, {
  get: (req) => users.map(u => ({ id: u.id, name: u.name, email: u.email }))
});

app.use('/v1', v1);
app.use('/v2', v2);

Common Mistakes

1. Version in Resource Body

Version should be in URL or header, not in the response body.

Links should point to the same version as the current request.

3. Mixed Version Formats

Some endpoints /v1/users, others /api/v2/users.

4. No Version in Media Type

If using content negotiation, media types must include version.

5. Breaking RESTful Conventions

Version shouldn't change the fundamental REST constraints.

Practice Questions

  1. What is the most RESTful versioning approach?
  2. How does HATEOAS interact with versioning?
  3. Should version be in the URL for REST APIs?
  4. How do you handle cross-version links?
  5. What happens to cached links when version changes?

Answers:

  1. Content negotiation with vendor media types.
  2. Links must point to the same version as the current resource.
  3. URI versioning is practical and widely used despite not being perfectly RESTful.
  4. Links should stay within the same version unless explicitly navigating to a different version.
  5. Cached links may point to a different version on subsequent requests.

Challenge: Implement RESTful versioning with HATEOAS links. Ensure all hypermedia links maintain version consistency.

FAQ

Can I have versioned and unversioned endpoints in the same API?

: Yes. Public endpoints are versioned; internal health/status endpoints may not be.

Does versioning affect API idempotency?

: No. Each version maintains its own idempotency guarantees.

Should versioning affect rate limits?

: Yes. Older versions may have different rate limit policies to encourage migration.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro