Atto
view release on metacpan or search on metacpan
lib/Atto.pm view on Meta::CPAN
my $args = {};
if ($env->{REQUEST_METHOD} eq 'GET') {
my $req = Plack::Request->new($env);
%$args = $req->query_parameters->flatten;
}
elsif ($env->{REQUEST_METHOD} eq 'POST') {
my $len = 0+($env->{CONTENT_LENGTH} || 0);
if ($len > 0) {
return $response->(400, "content type not provided") unless defined $env->{CONTENT_TYPE};
if ($env->{CONTENT_TYPE} eq 'application/json') {
my $nread = $env->{'psgi.input'}->read(my $content, $len);
return $response->(400, sprintf("expected %d bytes (from content-length), got %d", $len, $nread)) if $nread != $len;
$args = eval { $json->decode($content) };
return $response->(400, $@) if $@;
}
elsif ($env->{CONTENT_TYPE} eq 'application/x-www-form-urlencoded') {
my $nread = $env->{'psgi.input'}->read(my $content, $len);
return $response->(400, sprintf("expected %d bytes (from content-length), got %d", $len, $nread)) if $nread != $len;
%$args = parse_urlencoded($content);
return $response->(400, $@) if $@;
}
else {
return $response->(400, "unknown content type");
}
}
}
else {
return $response->(405, "request method must be POST or GET (not $env->{REQUEST_METHOD})");
}
# XXX prototypes
my @args =
ref $args eq 'ARRAY' ? @$args :
ref $args eq 'HASH' ? %$args :
($args);
my $ret = eval { $methods->{$method}->(@args) };
return $response->(500, "method call failed: $@") if $@;
return $response->(200, $ret);
}
}
1;
__END__
=pod
=encoding UTF-8
=for markdown [](http://travis-ci.org/robn/Atto)
=head1 NAME
Atto - A tiny microservice builder
=head1 SYNOPSIS
use Atto qw(hello);
sub hello {
my (%args) = @_;
my $name = $args{name} // "world";
return "hello $name";
}
Atto->psgi;
=head1 WARNING
This module is experimental. I think the idea is sound but I haven't used it
enough to know if it needs to offer more functions. Take care when using this
in your own code. If you do use it, please let me know!
=head1 DESCRIPTION
Atto makes it trivial to create HTTP+JSON microservices out of regular Perl
code.
Adding it to your code is simple. When you C<use Atto>, pass it it a list of
methods (subs) in the same package that you want to make available to the
network:
use Atto qw(hello);
Then, at the end of your program (or module!), call C<Atto-E<gt>psgi>. This returns a
PSGI application that can be consumed by C<plackup>.
$ plackup hello.pl
HTTP::Server::PSGI: Accepting connections at http://0:5000/
To call your methods from the network, send a POST request with the method
(sub) name in the URL:
$ curl -XPOST http://localhost:5000/hello
"hello world"
To pass arguments to the method, encode them as JSON in the request body and
add a C<Content-type: application/json> header to the request:
$ curl -XPOST -d '{"name":"dave"}' -H 'Content-type: application/json' http://localhost:5000/hello
"hello dave"
Arguments are flattened just like in Perl, so passing a JSON array or object
will do what you expect.
Alternatively, you can pass a hash via form parameters, which is less
expressive but easier in many scenarios:
$ curl -d 'name=dave' http://localhost:5000/hello
"hello dave"
( run in 2.505 seconds using v1.01-cache-2.11-cpan-df04353d9ac )