Skip to content

Response API

The response module provides the PlinxResponse class, which handles HTTP response generation in Plinx applications. This class offers a simple interface for setting response content, status codes, and headers.

PlinxResponse Class

plinx.response.PlinxResponse

Response class for the Plinx web framework.

This class provides a simple interface for constructing HTTP responses, with high-level helpers for common response types like JSON and plain text. It wraps WebOb's Response for actual WSGI compliance and output generation.

The class provides multiple ways to set response content:

  1. Set the text attribute for plain text responses
  2. Set the json attribute for JSON responses
  3. Set the body attribute directly for binary data

It also allows setting status codes, content types, and custom headers.

Examples:

Plain text response:

def handler(request, response):
    response.text = "Hello, World!"
    response.status_code = 200  # Optional, defaults to 200

JSON response:

def handler(request, response):
    response.json = {"message": "Hello, World!"}
    # Content-Type will automatically be set to application/json

Custom headers:

def handler(request, response):
    response.text = "Not Found"
    response.status_code = 404
    response.headers["X-Custom-Header"] = "Value"

Source code in plinx/response.py
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class PlinxResponse:
    """
    Response class for the Plinx web framework.

    This class provides a simple interface for constructing HTTP responses,
    with high-level helpers for common response types like JSON and plain text.
    It wraps WebOb's Response for actual WSGI compliance and output generation.

    The class provides multiple ways to set response content:

    1. Set the `text` attribute for plain text responses
    2. Set the `json` attribute for JSON responses
    3. Set the `body` attribute directly for binary data

    It also allows setting status codes, content types, and custom headers.

    Examples:
        Plain text response:
        ```python
        def handler(request, response):
            response.text = "Hello, World!"
            response.status_code = 200  # Optional, defaults to 200
        ```

        JSON response:
        ```python
        def handler(request, response):
            response.json = {"message": "Hello, World!"}
            # Content-Type will automatically be set to application/json
        ```

        Custom headers:
        ```python
        def handler(request, response):
            response.text = "Not Found"
            response.status_code = 404
            response.headers["X-Custom-Header"] = "Value"
        ```
    """

    def __init__(self):
        """
        Initialize a new response object.

        Sets up default values for the response attributes:
        - json: None (will be serialized to JSON if set)
        - text: None (will be encoded to UTF-8 if set)
        - content_type: None (will be set based on response type)
        - body: Empty bytes (raw response body)
        - status_code: 200 (OK)
        - headers: Empty dict (custom HTTP headers)
        """
        self.json = None
        self.text = None
        self.content_type = None
        self.body = b""
        self.status_code = 200
        self.headers = {}

    def __call__(
        self,
        environ: WSGIEnvironment,
        start_response: StartResponse,
    ) -> Iterable[bytes]:
        """
        WSGI callable interface for the response.

        This makes the response object act as a WSGI application,
        which is required for compatibility with WSGI servers.
        It delegates the actual WSGI handling to WebOb's Response.

        Args:
            environ: The WSGI environment dictionary
            start_response: The WSGI start_response callable

        Returns:
            An iterable of bytes representing the response body
        """

        self.set_body_and_content_type()

        response = WebObResponse(
            body=self.body,
            content_type=self.content_type,
            status=self.status_code,
            headers=self.headers,
        )
        return response(environ, start_response)

    def set_body_and_content_type(self):
        """
        Prepare the response body and content type based on the response attributes.

        This method is called automatically before the response is returned.
        It handles the conversion of high-level response attributes (`json`, `text`)
        into the raw response body and appropriate content type.

        The priority order is:
        1. If `json` is set, encode it as JSON and set content_type to application/json
        2. If `text` is set, encode it as UTF-8 and set content_type to text/plain
        3. Otherwise, use the existing `body` and `content_type`
        """
        if self.json is not None:
            self.body = json.dumps(self.json).encode("UTF-8")
            self.content_type = "application/json"
        elif self.text is not None:
            self.body = (
                self.text.encode("utf-8") if isinstance(self.text, str) else self.text
            )
            self.content_type = "text/plain"

        if self.content_type is not None:
            self.headers["Content-Type"] = self.content_type

Functions

__call__(environ, start_response)

WSGI callable interface for the response.

This makes the response object act as a WSGI application, which is required for compatibility with WSGI servers. It delegates the actual WSGI handling to WebOb's Response.

Parameters:

Name Type Description Default
environ WSGIEnvironment

The WSGI environment dictionary

required
start_response StartResponse

The WSGI start_response callable

required

Returns:

Type Description
Iterable[bytes]

An iterable of bytes representing the response body

Source code in plinx/response.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def __call__(
    self,
    environ: WSGIEnvironment,
    start_response: StartResponse,
) -> Iterable[bytes]:
    """
    WSGI callable interface for the response.

    This makes the response object act as a WSGI application,
    which is required for compatibility with WSGI servers.
    It delegates the actual WSGI handling to WebOb's Response.

    Args:
        environ: The WSGI environment dictionary
        start_response: The WSGI start_response callable

    Returns:
        An iterable of bytes representing the response body
    """

    self.set_body_and_content_type()

    response = WebObResponse(
        body=self.body,
        content_type=self.content_type,
        status=self.status_code,
        headers=self.headers,
    )
    return response(environ, start_response)
__init__()

Initialize a new response object.

Sets up default values for the response attributes: - json: None (will be serialized to JSON if set) - text: None (will be encoded to UTF-8 if set) - content_type: None (will be set based on response type) - body: Empty bytes (raw response body) - status_code: 200 (OK) - headers: Empty dict (custom HTTP headers)

Source code in plinx/response.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def __init__(self):
    """
    Initialize a new response object.

    Sets up default values for the response attributes:
    - json: None (will be serialized to JSON if set)
    - text: None (will be encoded to UTF-8 if set)
    - content_type: None (will be set based on response type)
    - body: Empty bytes (raw response body)
    - status_code: 200 (OK)
    - headers: Empty dict (custom HTTP headers)
    """
    self.json = None
    self.text = None
    self.content_type = None
    self.body = b""
    self.status_code = 200
    self.headers = {}
set_body_and_content_type()

Prepare the response body and content type based on the response attributes.

This method is called automatically before the response is returned. It handles the conversion of high-level response attributes (json, text) into the raw response body and appropriate content type.

The priority order is: 1. If json is set, encode it as JSON and set content_type to application/json 2. If text is set, encode it as UTF-8 and set content_type to text/plain 3. Otherwise, use the existing body and content_type

Source code in plinx/response.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def set_body_and_content_type(self):
    """
    Prepare the response body and content type based on the response attributes.

    This method is called automatically before the response is returned.
    It handles the conversion of high-level response attributes (`json`, `text`)
    into the raw response body and appropriate content type.

    The priority order is:
    1. If `json` is set, encode it as JSON and set content_type to application/json
    2. If `text` is set, encode it as UTF-8 and set content_type to text/plain
    3. Otherwise, use the existing `body` and `content_type`
    """
    if self.json is not None:
        self.body = json.dumps(self.json).encode("UTF-8")
        self.content_type = "application/json"
    elif self.text is not None:
        self.body = (
            self.text.encode("utf-8") if isinstance(self.text, str) else self.text
        )
        self.content_type = "text/plain"

    if self.content_type is not None:
        self.headers["Content-Type"] = self.content_type

Examples

Text Responses

@app.route("/hello")
def hello(request, response):
    response.text = "Hello, World!"
    response.status_code = 200  # Optional, defaults to 200

JSON Responses

@app.route("/api/data")
def get_data(request, response):
    response.json = {
        "name": "Plinx",
        "version": "1.0.1",
        "features": ["routing", "middleware", "orm"]
    }
    # Content-Type is automatically set to application/json

Custom Status Codes

from plinx.status_codes import StatusCodes

@app.route("/not-found")
def not_found(request, response):
    response.text = "Resource not found"
    response.status_code = StatusCodes.NOT_FOUND.value  # 404

Setting Headers

@app.route("/download")
def download(request, response):
    response.text = "File content goes here"
    response.headers["Content-Type"] = "text/plain"
    response.headers["Content-Disposition"] = "attachment; filename=sample.txt"

Binary Responses

@app.route("/image")
def get_image(request, response):
    with open("image.png", "rb") as f:
        response.body = f.read()
    response.content_type = "image/png"

Response Properties

Property Type Description
text str Text content of the response (sets content type to "text/plain")
json Any JSON-serializable content (sets content type to "application/json")
body bytes Raw response body as bytes
content_type str MIME type of the response (e.g., "text/html", "application/json")
status_code int HTTP status code (default: 200)
headers dict Dictionary of HTTP headers

Content Type Handling

The PlinxResponse class automatically sets the Content-Type header based on how you set the response content:

  1. If you set response.json, the content type is set to "application/json"
  2. If you set response.text, the content type is set to "text/plain"
  3. If you set response.body directly, you should also set response.content_type manually

Internal Workflow

When a response is being prepared to be sent back to the client:

  1. The set_body_and_content_type() method is called to ensure the response body and headers are properly prepared
  2. The response is converted to a WebOb Response object
  3. The WebOb Response handles the actual WSGI response generation

Custom Response Classes

If you need to extend the PlinxResponse class with additional functionality, you can create a subclass:

from plinx.response import PlinxResponse

class HTMLResponse(PlinxResponse):
    def set_html(self, html_content):
        self.body = html_content.encode("utf-8")
        self.content_type = "text/html"

    def render_template(self, template_name, **context):
        # Simple template rendering example
        with open(f"templates/{template_name}.html") as f:
            template = f.read()

        # Very basic template substitution
        for key, value in context.items():
            template = template.replace(f"{{{{{key}}}}}", str(value))

        self.set_html(template)

To use your custom response class, you would need to modify your application to create instances of your class instead of the standard PlinxResponse.