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 [![Build Status](https://secure.travis-ci.org/robn/Atto.png)](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 )