How to Mock an Ambassador Edge Proxy in Python

Build a lightweight mock Ambassador edge proxy with Python's http.server that responds to health and user endpoint requests for local development and testing.

Easy Python 3.7+ Aug 9, 2026 Microservices patterns 13 views 0 copies

Python code

34 lines
Python 3.7+
import http.server
import json
import urllib.parse
import threading

class AmbassadorProxyHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        parsed = urllib.parse.urlparse(self.path)
        if parsed.path == "/health":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps({"status": "healthy"}).encode())
        elif parsed.path == "/users":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps({"users": [{"id": 1, "name": "Alice"}]}).encode())
        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b'{"error": "not found"}')

    def log_message(self, format, *args):
        pass

def run_mock_proxy(port=8080, host="127.0.0.1"):
    server = http.server.ThreadingHTTPServer((host, port), AmbassadorProxyHandler)
    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()
    return f"Mock Ambassador proxy running at http://{host}:{port}"

if __name__ == "__main__":
    print(run_mock_proxy())

Output

stdout
Mock Ambassador proxy running at http://127.0.0.1:8080

# GET /health returns:
{"status": "healthy"}

# GET /users returns:
{"users": [{"id": 1, "name": "Alice"}]}

# Any other path returns:
{"error": "not found"}

How it works

The ThreadingHTTPServer in the stdlib handles each request in its own thread, which lets the mock proxy stay responsive under concurrent calls from a service mesh or gateway. The handler extends BaseHTTPRequestHandler to intercept GET requests and route them to simple JSON responses mimicking Ambassador's health or service endpoints. Using urllib.parse.urlparse splits the request path from query parameters so routing logic stays clean. The daemon thread allows the server to start and stop cleanly alongside your test suite.

Common mistakes

  • Starting the server on port 0 to get a random free port, then trying to use port 8080 in tests — keep track of the actual assigned port.
  • Forgetting to override `log_message` — the default logging prints every request and clutters test output.
  • Shutting down with `server.shutdown()` while requests are in flight — use `server.server_close()` after a clean stop.
  • Binding to 127.0.0.1 when the service under test runs in Docker or a VM — use 0.0.0.0 to expose the mock externally.

Variations

  1. Use `http.server.HTTPServer` instead of `ThreadingHTTPServer` if your test suite never issues concurrent requests.
  2. Implement `do_POST` and `do_DELETE` to mock writable Ambassador endpoints like route updates or auth tokens.

Real-world use cases

  • Stand in for an Ambassador gateway during local microservice development so you can test routing logic without standing up a full mesh.
  • Provide deterministic health and user responses in CI pipelines, letting integration tests assert service-to-service behavior without external dependencies.
  • Mock Ambassador's auth or rate-limit responses when load-testing downstream services, isolating them from real gateway behavior.

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.