Building a Simple JSON Mock Server with Python

How to build a lightweight JSON mock server using Python's built-in wsgiref library, with WSGI application basics and CORS support for frontend development.

During frontend development or API integration testing, a mock server is very useful when the backend API is not yet ready or when you want to simulate specific responses. Here, we introduce how to build a simple mock server that returns JSON data using Python’s standard library wsgiref.

Starting a Web Server Using WSGI (Web Server Gateway Interface)

wsgiref.simple_server is the reference implementation of WSGI, the standard interface between Python web applications and web servers. It can be used to build a simple HTTP server.

from wsgiref.simple_server import make_server
import json

# Port number for the server to listen on
PORT = 8081

# Mock data definitions
# Set JSON data to return based on PATH_INFO (request path)
MOCK_DATA_SETTINGS = [
    {
        "PATH": "/api/1",
        "VALUE": {
            "items": [
                {"item1": "test1"},
                {"item2": "test2"}
            ]
        }
    },
    {
        "PATH": "/api/2",
        "VALUE": {
            "items2": [
                {"itemA": "testA"},
                {"itemB": "testB"}
            ]
        }
    }
]

def application(environ, start_response):
    """
    WSGI application entry point.
    Returns appropriate JSON data based on the request.
    """
    path = environ.get("PATH_INFO", "/") # Get the request path

    for setting in MOCK_DATA_SETTINGS:
        # Check if the request path starts with the configured path
        if path.startswith(setting["PATH"]):
            status = '200 OK' # HTTP status code
            headers = [
                ('Content-type', 'application/json; charset=utf-8'), # Specify JSON format
                ('Access-Control-Allow-Origin', '*'), # CORS support (allow access from all origins)
            ]
            start_response(status, headers) # Send response headers

            # Encode JSON data as UTF-8 and return
            return [json.dumps(setting["VALUE"]).encode("utf-8")]

    # If no path matches
    status = '404 Not Found'
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, headers)
    return [b"404 Not Found"]

if __name__ == "__main__":
    # Start the server
    # make_server(hostname, port_number, WSGI_application)
    httpd = make_server('', PORT, application)
    print(f"Serving on port {PORT}...")
    print("Access URLs like: http://localhost:8081/api/1")
    print("Press Ctrl+C to quit.")
    httpd.serve_forever()

Code Explanation

  • make_server('', PORT, application):
    • '': When no hostname is specified, connections from all available interfaces are accepted (equivalent to 0.0.0.0).
    • PORT: The port number the server listens on.
    • application: The WSGI application object. This function is called every time an HTTP request arrives.
  • environ: A dictionary containing environment variables with HTTP request information (path, headers, etc.). PATH_INFO is the path portion of the request.
  • start_response(status, headers): A function for setting the response status code and headers.
  • json.dumps(data).encode("utf-8"): Converts a Python dictionary to a JSON string and then encodes it as bytes. WSGI applications must return byte strings.
  • Access-Control-Allow-Origin: *: This header enables CORS (Cross-Origin Resource Sharing) support. It is needed to allow JavaScript requests from different origins (domains, protocols, ports). While * is commonly used during development to allow all origins, restricting to specific origins is recommended in production environments.

Running this script starts a web server on the specified port, and accessing paths like /api/1 or /api/2 returns the corresponding JSON data.

References