How to Build a Batch Operations Multi-Status 207 Mock Server in Python

Build a mock HTTP server that accepts a batch of operations and returns HTTP 207 Multi-Status with per-operation status codes in JSON.

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

Python code

41 lines
Python 3.9+
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class BatchHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path != "/batch":
            self.send_response(404)
            self.end_headers()
            return

        content_length = int(self.headers.get("Content-Length", 0))
        body = json.loads(self.rfile.read(content_length) or b"{}")
        operations = body.get("operations", [])

        results = []
        for op in operations:
            op_id = op.get("id")
            action = op.get("action")
            if action == "create":
                results.append({"id": op_id, "status": 201, "message": "Created"})
            elif action == "update":
                results.append({"id": op_id, "status": 200, "message": "Updated"})
            elif action == "delete":
                results.append({"id": op_id, "status": 200, "message": "Deleted"})
            else:
                results.append({"id": op_id, "status": 422, "message": "Invalid action"})

        response_body = json.dumps({"results": results}).encode()
        self.send_response(207)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(response_body)))
        self.end_headers()
        self.wfile.write(response_body)

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

if __name__ == "__main__":
    server = HTTPServer(("localhost", 8080))
    print("Batch server running on http://localhost:8080")
    server.serve_forever()

Output

stdout
Batch server running on http://localhost:8080

# When POSTing to /batch with operations, the response will be 207 with:
{
  "results": [
    {"id": "1", "status": 201, "message": "Created"},
    {"id": "2", "status": 200, "message": "Updated"},
    {"id": "3", "status": 422, "message": "Invalid action"}
  ]
}

How it works

The handler uses BaseHTTPRequestHandler to create a simple HTTP server without third-party dependencies. The do_POST method reads the request body, parses JSON, and iterates over operations, building a list of per-operation statuses. It always responds with HTTP 207 Multi-Status as defined by WebDAV, even if individual operations fail. This pattern is common in APIs that need to report partial success or failure for batch requests.

Common mistakes

  • Not checking Content-Length and reading too little or too much data
  • Returning 404 for unknown paths but still sending a JSON body
  • Forgetting to set Content-Type header to application/json
  • Not handling malformed JSON input gracefully

Variations

  1. Use Flask or FastAPI with a JSON request validation library instead of raw BaseHTTPRequestHandler
  2. Add async support with aiohttp or Tornado for higher concurrency

Real-world use cases

  • Mocking an external API's batch endpoints during integration testing to simulate mixed success/failure responses.
  • Building a lightweight internal tool that accepts bulk data operations and reports per-item errors for data cleanup.
  • Implementing a rate-limiting or throttling proxy that forwards batch requests and aggregates statuses for clients.

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.