Build a Mock REST API with PUT and GET in Python

A minimal mock REST server implementing idempotent PUT for resource replacement and GET for retrieval, built with Python's http.server module.

Medium Python 3.9+ Aug 9, 2026 API design & gRPC 15 views 0 copies

Python code

49 lines
Python 3.9+
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
from urllib.parse import urlparse

mock_db = {}

class MockAPIHandler(BaseHTTPRequestHandler):
    def do_PUT(self):
        parsed = urlparse(self.path)
        resource_id = parsed.path.strip("/").split("/")[-1]
        content_length = int(self.headers.get("Content-Length", 0))
        payload = json.loads(self.rfile.read(content_length) or b"{}")

        mock_db[resource_id] = payload

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(json.dumps({
            "id": resource_id,
            "data": payload,
            "message": "Resource replaced successfully (idempotent)"
        }).encode())

    def do_GET(self):
        parsed = urlparse(self.path)
        resource_id = parsed.path.strip("/").split("/")[-1]

        if resource_id in mock_db:
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps(mock_db[resource_id]).encode())
        else:
            self.send_response(404)
            self.end_headers()

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


def run_server():
    server = HTTPServer(("localhost", 8000), MockAPIHandler)
    print("Mock REST server running on http://localhost:8000")
    server.serve_forever()


if __name__ == "__main__":
    run_server()

Output

stdout
Mock REST server running on http://localhost:8000

# Client requests:
curl -X PUT http://localhost:8000/users/42 -d '{"name": "Alice"}'
{"id": "42", "data": {"name": "Alice"}, "message": "Resource replaced successfully (idempotent)"}

curl http://localhost:8000/users/42
{"name": "Alice"}

curl http://localhost:8000/users/99
(404 response)

# Repeating the same PUT returns the same 200 response — idempotent behavior:

How it works

The do_PUT method reads the request body with Content-Length to avoid blocking, then parses it as JSON. Storing the payload in a dictionary keyed by the resource ID makes replacement idempotent — repeating the same PUT yields identical results. The do_GET handler looks up the ID and returns 404 for missing resources. All state lives in-memory, so the mock resets on restart, which is ideal for tests or local prototyping.

Common mistakes

  • Forgetting to handle `Content-Length` when reading the request body, causing hangs or partial reads
  • Assuming the resource ID is always numeric; the URL path parsing may need validation
  • Not setting `Content-Type` headers, leading to clients misinterpreting responses

Variations

  1. Use Flask or FastAPI for more routing features, validation, and auto-generated docs
  2. Add DELETE support by removing the key from the dictionary

Real-world use cases

  • Stubbing a backend API during frontend development so UI work isn't blocked by service availability.
  • Providing a throwaway test double in integration tests to verify client retry and error-handling logic.
  • Simulating a resource store for acceptance tests of PUT idempotency contract requirements.

Sponsored

Run this sample

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

Open editor

More from API design & gRPC

Related tutorials and quizzes for this topic.