Created
June 20, 2017 19:54
-
-
Save anonymous/80f6798530a3811335a065e2f9623779 to your computer and use it in GitHub Desktop.
Second take at web dispatching framework based on simple multi dispatching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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