Skip to content

Instantly share code, notes, and snippets.

Created June 20, 2017 19:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/80f6798530a3811335a065e2f9623779 to your computer and use it in GitHub Desktop.
Save anonymous/80f6798530a3811335a065e2f9623779 to your computer and use it in GitHub Desktop.
Second take at web dispatching framework based on simple multi dispatching
class HTTP::Request {
has $.path is rw;
has $.method is rw;
}
class HTTP::Response {
has $.status is rw;
has $.message is rw;
}
class RequestRoot {}
class FooContext {
has Int $.foo_id;
}
class BarContext {
has FooContext $.foocontext;
has Int $.bar_id;
}
subset StrToInt of Str where +*;
multi dispatch( RequestRoot $c,
HTTP::Request $req, HTTP::Response $res ) {
$res.status = 200;
$res.message = "Final request in the chain on the root context";
}
multi dispatch( RequestRoot $c, 'foo', Int(StrToInt) $foo_id, *@remaining ) {
dispatch(FooContext.new(:foo_id($foo_id)), |@remaining);
}
multi dispatch( FooContext $c,
HTTP::Request $req, HTTP::Response $res ) {
$res.status = 200;
$res.message = "Final request in the chain for foo " ~ $c.foo_id;
}
multi dispatch( FooContext $c, 'bar', Int(StrToInt) $bar_id, *@remaining ) {
dispatch(BarContext.new(:foocontext($c), :bar_id($bar_id)), |@remaining);
}
subset GET of HTTP::Request where { .method eq 'GET' };
multi dispatch( BarContext $c,
GET $req, HTTP::Response $res ) {
$res.status = 200;
$res.message = "Final action in the chain for foo " ~ $c.foocontext.foo_id ~
" bar " ~ $c.bar_id;
}
multi dispatch( BarContext $c,
HTTP::Request $req, HTTP::Response $res ) {
$res.status = 405;
$res.message = "method not allowed: foo " ~ $c.foocontext.foo_id ~
" bar " ~ $c.bar_id;
}
sub handle_request(HTTP::Request $req) {
my @parts = grep { $_ ne "" }, split /\//, $req.path;
my $res = HTTP::Response.new();
dispatch(RequestRoot, |@parts, $req, $res);
return $res;
CATCH {
when X::Multi::NoMatch {
return HTTP::Response.new(:status(404),
:message($req.path ~ " Not found "))
}
default {
return HTTP::Response.new(:status(500),
:message($req.path ~ " Error: " ~ .gist))
}
}
}
my @tests = (
['GET', '/foo/1/bar/2'],
['GET', '/foo/lalala/bar/2'],
['GET', '/foo/1'],
['GET', '/'],
['GET', '/foo'],
['POST', '/foo/1/bar/2'],
['POST', '/foo/lalala/bar/2'],
['POST', '/foo/1'],
['POST', '/'],
['POST', '/foo'],
);
for @tests -> $test {
my $method = $test[0];
my $path = $test[1];
my $req = HTTP::Request.new(:method($method), :path($path));
my $res = handle_request($req);
say join " ", $req.method, $req.path;
say join " ", $res.status, $res.message;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment