How to Mock Service Versioning URI in Python

Run a minimal HTTP server in Python that routes requests to different versions of a service URI like /v1/users vs /v2/users.

Easy Python 3.8+ Aug 9, 2026 Microservices patterns 11 views 0 copies

Python code

31 lines
Python 3.8+
from http.server import HTTPServer, BaseHTTPRequestHandler
import json


class VersionedHandler(BaseHTTPRequestHandler):
    def _send_json(self, payload, status=200):
        body = json.dumps(payload).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        if self.path.startswith("/v1/users"):
            self._send_json({"api_version": "v1", "endpoint": "users"})
        elif self.path.startswith("/v2/users"):
            self._send_json({"api_version": "v2", "endpoint": "users"})
        else:
            self._send_json({"error": "not found"}, status=404)


def run_server(port=8000):
    server = HTTPServer(("127.0.0.1", port), VersionedHandler)
    print(f"Serving on http://127.0.0.1:{port}")
    server.handle_request()  # handle one request for demo
    server.server_close()


if __name__ == "__main__":
    run_server()

Output

stdout
Serving on http://127.0.0.1:8000

How it works

The code subclasses BaseHTTPRequestHandler to implement a tiny, dependency-free HTTP server. Each incoming GET request is inspected via self.path, and simple startswith checks route /v1/users and /v2/users to different handler branches. The _send_json helper centralizes JSON serialization, headers, and writing the response body, so every endpoint returns consistent JSON. Only one request is handled before the server closes, which keeps this demo deterministic for testing or CI. Starting the server from if __name__ == "__main__" lets you import the handler elsewhere without accidentally running a server.

Common mistakes

  • Forgetting to set Content-Length, which can cause clients to hang waiting for the response body.
  • Using exact equality instead of startswith, breaking requests with trailing slashes or query strings like /v2/users?page=1.
  • Attempting multiple handle_request calls in a loop without threading, which would serve requests serially.
  • Not URL-decoding the path when version segments might contain encoded characters.

Variations

  1. Use `server.serve_forever()` in a background thread to handle multiple requests concurrently (still simple).
  2. Check version by parsing `pathlib.PurePosixPath(self.path)` segments instead of string startswith for more robust routing.

Real-world use cases

  • Local smoke tests of API endpoints before deploying versioned services.
  • Stub backends for frontend development or integration tests when real services are unavailable.
  • Quick demos or educational examples that show how versioned route matching works in microservice gateways.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Microservices patterns

Related tutorials and quizzes for this topic.