2012 Feed

PSGI

OX - 2012-12-07

Overview

PSGI is the Perl (web) Server Gateway Interface. It defines a protocol for Perl web applications to communicate with web servers in such a way that applications can just write code using the protocol and automatically work on any web server that supports PSGI (which is most of them, these days). It consists of two main parts: the request API and the response API. A PSGI application is just a subroutine which takes a request environment hashref as a parameter and returns a valid response.

In OX, you create a PSGI application by calling the to_app method on an application instance. This is also used as the return value of the router block, to make writing short applications easier.

Request

The request environment is a hashref containing all of the request data. You can access the actual request environment in OX via the env method on an OX::Request object. It is typically easier, however, to access the data via the methods on the request object (which we will discuss tomorrow). The raw environment hashref is available if you need to do more complicated things, or if OX::Request doesn't expose the data that you need.

One thing that is exposed in the environment that may be useful is information about the capabilities of the server you are currently running on. PSGI discourages relying on specific server implementations if at all possible - any functionality you may need from a server should be exposed in a general way, so that other servers can also implement it. Some examples are:

  • psgi.multithread

    The server runs multiple requests simultaneously in separate threads.

  • psgi.multiprocess

    The server runs multiple requests simultaneously in separate processes.

  • psgi.run_once

    The server only runs a single request in a given process (like CGI).

  • psgi.nonblocking

    The server supports non-blocking operation via an event loop. You should make sure that your application uses a compatible event loop if you want to interact with it.

  • psgi.streaming

    The server supports streaming responses. These will be described in the next section.

Response

Understanding how the response protocol works is much more useful, since, as mentioned previously, action subroutines in OX can return not only a string or a response object, but also any valid PSGI response. A PSGI response is either a three-element array reference, or (if psgi.streaming is true) a code reference. The three elements of the array reference are, in order:

  • The response code. This is a single integer between 100 and 599.

  • An arrayref containing the headers, in key-value pairs. It is an arrayref rather than a hashref because the HTTP specification allows certain headers to be specified multiple times. This must contain at least a Content-Type entry, unless the response code is 1xx, 204, or 304.

  • The response body. This can either be an arrayref of strings or a filehandle of some sort.

For instance, a simple response could look like this:


1: 
 

[ 200, [ 'Content-Type' => 'text/plain' ], [ "Hello world!" ] ]
 

In addition, if the psgi.streaming variable is true in the environment, the response can be a coderef. This coderef will receive a callback subroutine as its only argument. You can use this callback in one of two ways.

The simplest way to use it is to just call the callback with a full response arrayref as described above. This can be useful if you are running on a nonblocking server, and want to not block the server while you wait for response data to be fetched.

For instance:


1: 
2: 
3: 
4: 
5: 

 

sub {
    my $responder = shift;
    my $data = slow_database_query();
    $responder->([200, ['Content-Type' => 'text/html'], [render($data)]]);
}

 

In addition, this form of response can be used for HTTP server push (also known as long-poll or Comet) applications. In these kinds of requests, the connection remains open, and the server streams data to the client, which reads it as it comes in. To support this, you can pass the callback an arrayref containing only the first two elements (response code and headers). The callback will then return an object which implements two methods, write and close, which can be used to send data to the client directly.

An example of this type of response:


1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 

 

sub {
    my $responder = shift;
    my $writer = $responder->([200, ['Content-Type' => 'application/json']]);
    while (my $event = get_next_event()) {
        $writer->write(encode_json($event) . "\n");
    }
    $writer->close;
}

 

response_cb

Middleware can be applied to any PSGI application, and if they need to modify the response, dealing with all of these different kinds of responses can be difficult. Plack provides Plack::Util::response_cb to handle this situation more conveniently. It takes a PSGI response and a coderef, and returns an updated PSGI response after having been filtered through the coderef. For instance:


1: 
2: 
3: 
4: 

 

$res = Plack::Util::response_cb($res, sub {
    my $res = shift;
    push @{ $res->[1] }, ('X-Foo' => 'Bar');
});

 

In this case, the response is updated in-place and returned (and the return value from the subroutine is ignored).

Alternatively, you can return a code reference from the subroutine, and it will be used as a content filter. For instance:


1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 

 

$res = Plack::Util::response_cb($res, sub {
    my $res = shift;
    return sub {
        my $chunk = shift;
        return unless defined $chunk;
        return uc($chunk);
    };
});

 
Gravatar Image This article contributed by: Jesse Luehrs <jesse.luehrs@iinteractive.com>