Application & Server Sides Of WSGI

In WSGI (Web Server Gateway Interface), there are two distinct components involved:

  1. Application Side (WSGI Application): This is the web application or framework that receives requests, processes them, and returns responses.
  2. Server Side (WSGI Server): This is the server that handles incoming HTTP requests, translates them into a WSGI-compatible format, and passes them to the WSGI application.

Both sides adhere to the WSGI specification, which enables them to work together, even if they’re developed independently.

WSGI Application Side

The application side is the Python web application or framework (e.g., Django, Flask) that processes incoming requests and sends back a response. The application follows a specific contract as defined by the WSGI specification.

Responsibilities of the WSGI Application:

  • Accepts the HTTP request in a standardized format.
  • Processes the request (e.g., routing, interacting with databases, generating HTML).
  • Returns a response to the WSGI server in the form of a status code, headers, and body.

The WSGI application must be a callable (typically a function or a class instance with a __call__ method) that follows a specific signature:

def my_wsgi_app(environ: dict, start_response) -> list:
    # Process the request
    response_body = b"Hello, WSGI World!"
    
    # Status and headers
    status = '200 OK'
    headers = [('Content-Type', 'text/plain')]
    
    # Call start_response to start the response
    start_response(status, headers)
    
    # Return the response body as a list of byte strings
    return [response_body]
  • environ: A dictionary containing all the request data (e.g., PATH_INFO, QUERY_STRING, REQUEST_METHOD).
  • start_response: A callable provided by the server that the application uses to start the HTTP response. It accepts the status code and headers.
  • The application returns an iterable (a list or generator) containing byte strings (the body of the response).

Application Side Workflow:

The WSGI server calls the application with the request data (environ) and the start_response function.

  1. The application processes the request.
  2. The application calls start_response with the status code and headers.
  3. The application returns an iterable (like a list or generator) containing the body of the HTTP response in byte strings.

WSGI Server Side

The server side is the WSGI server (e.g., uWSGI, Gunicorn), which sits between the web server (e.g., Nginx, Apache) and the WSGI application. The server is responsible for handling HTTP requests and passing them to the WSGI application in a format defined by the WSGI specification.

Responsibilities of the WSGI Server:

Receives the HTTP request from the web server (Nginx, Apache).

  • Constructs the environ dictionary: The WSGI server converts the HTTP request into a dictionary (environ) following CGI-like conventions, which contains all the necessary request metadata.
  • Calls the WSGI application: It passes the environ and start_response callable to the application.
  • Handles the response: It takes the response generated by the WSGI application and sends it back to the web server, which then delivers it to the client.

Server Side Workflow:

The WSGI server receives the HTTP request from the web server.

  1. It builds the environ dictionary containing request metadata.
  2. It invokes the WSGI application with environ and start_response.
  3. The WSGI application generates the response.
  4. The WSGI server collects the response from the application and sends it back to the web server.

Here’s a pseudo-code example showing how a WSGI server might work internally:

class WSGIServer:
    
    def __init__(self, application):
        self.application = application
    
    def handle_request(self, request):
        # Create the environ dictionary from the HTTP request
        environ = self.build_environ(request)
        # Define the start_response callable
        def start_response(status, headers):
            self.send_response(status, headers)
        
        # Call the WSGI application
        response_body = self.application(environ, start_response)
        # Send the response to the client
        for data in response_body:
            self.send_data(data)
  • build_environ(request): Converts the HTTP request into the environ dictionary.
  • start_response(status, headers): Prepares the status and headers to send back to the client.
  • send_data(data): Sends the response body to the client.

Key Points of WSGI Specification:

  1. Environ Dictionary:
  • Contains CGI-like variables (e.g., REQUEST_METHOD, PATH_INFO, QUERY_STRING).
  • Must include WSGI-specific variables like wsgi.version, wsgi.input, and wsgi.errors.
  1. Start Response:
  • The application must call start_response before sending the body of the response.
  • The WSGI server provides the start_response callable.
  • The start_response callable accepts a status string (e.g., ‘200 OK’) and headers (a list of tuples).
  1. Response:
  • The WSGI application must return an iterable containing byte strings.
  • The response body is transferred to the server, which passes it back to the client.

Track your progress

Mark this subtopic as completed when you finish reading.