2

I am looking at a strange implementation of a web service using Plack, and I can't quite understand how all the pieces come together (a coworker copied and modified it from a tutorial, but he can't find the tutorial any more).

First of all, this code does work, as strange as it is.

Here is what I know: At a high level, this code implements a web service. Due to the conventions of Plack, this file has to return a method which takes request parameters as input and then returns a HTTP code and body. That is why there is the "my $app = sub {". Assuming this is the last line in the file (which is app.psgi) it will be the return value of the file.

I don't understand some things beginning with "return sub." I believe that is essentially overriding "my $app = sub {", because now that is the function that the file will return.

However, that might be wrong because it seems to take different arguments. Instead of taking $env (which is information about the request including GET params), it takes an argument $responder. When I print out the type of that, it is CODE. I don't know what that means.

Then the next line seems to simultaneously return an HTTP code (beginning our response) and get a writer for writing additional data. Everything after that makes sense.

So in summary I need help understanding what this second method is doing, and what the nature of its arguments are. Thanks very much in advance.

use strict;
use warnings;

use Plack::Request;
use POSIX ":sys_wait_h";
use IO::Handle;

STDOUT->autoflush(1);
my $app = sub {
    my $env = shift;
    my $req = Plack::Request->new($env);
    print "Worker PID: $$\n";
    my $params = $req->parameters();

    return sub {
        my $responder = shift;

        #this will print "responder type: CODE"
        print "responder type: " . (ref $responder) . "\n";

        my $writer = $responder->(
            [ 200, [ 'Content-Type', 'application/html' ]]);
        $writer->write("some content");
        $writer->close();
    }
}
Stephen
  • 8,508
  • 12
  • 56
  • 96

1 Answers1

3

Using return in a sub takes effect only when the sub is being run, not when it's being returned.

Instead of directly returning the response, the application can return a code reference:

Applications MUST return a response as either a three element array reference, or a code reference for a delayed/streaming response.

The details are described under Delayed Response and Streaming Body in PSGI.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • Thanks, this is exactly what I wanted. It's a little unclear when/how the code reference is actually called, but can we assume the server immediately calls it? – Stephen Jan 23 '18 at 22:53
  • Incidentally do you think the STDOUT->autoflush(1) is really necessary? I can't quite tell what that is for. I believe it is made possible by IO::Handle, but those docs don't directly document an autoflush command, they only make passing reference to it. – Stephen Jan 23 '18 at 22:55
  • See `$|` in [perlvar](http://p3rl.org/perlvar) for the explanation of `autoflush`. – choroba Feb 15 '18 at 16:18