Perl REST flow layout

强颜欢笑 提交于 2019-12-05 02:31:57

问题


I'm using Apache and Perl (modperl), with Handlers to handle requests. I'm new to this, and I'm not quite sure how to lay things out in a sensible way.

Right now I have the following:

package MyClass::Handler;

use warnings;
use strict;
# includes

our %action = ( 
   'a' => \&a,
   # And more
);

sub handler {
    my $a = shift;
    my $r = Apache2::Request->new($a);

    # Do things

    return Apache2::Const::OK();
}

Should I have a different file for each "space"? Using stackoverflow as a template, do I need a User.pm for all the User management? A Story.pm for stories?


回答1:


You might be interested in the excellent CGI::Application framework from CPAN. Despite its name, it works both under normal CGI and mod_perl. It's designed to make the task of setting up web-app dispatch tables very simple. Throw in CGI::Application::Dispatch and you get nice REST-like URLs.




回答2:


For a recent project, I wrote a custom configuration handler which implemented a new ResourceURI config setting. This let me put configuration lines into httpd.conf like this:

ResourceURI SomeResource GET,POST,DELETE "^/...$"

The three arguments are my resource class name, the list of HTTP methods which the resource can respond to, and a regex that matches the URI(s) for the resource.

The custom configuration class replaces each of these lines with a block like this:

PerlModule Handler::{resource class}
PerlModule Resource::{resource class}

<Location ~ "{uri regex}">
    Order allow,deny
    Allow from all

    <LimitExcept {allowed methods}>
        Order deny,allow
        Deny from all
    </LimitExcept>

    SetHandler modperl
    PerlHandler Handler

    PerlSetVar Resource {resource class}
</Location>

This takes care of loading my classes, lets Apache reject invalid methods, sets a flag to indicate which resource to route to, and passes all requests through my Handler::handler() function.

package Handler;

sub handler {
    my $r = shift;
    my $resource_class = 'Resource::' . $r->dir_config('Resource');
    my $handler_class = 'Handler::' . $r->dir_config('Resource');
    my $resource = $resource_class->new($r, $r->uri);
    return Apache2::Const::HTTP_NOT_FOUND unless $resource;
    my $method = $r->method();
    return Apache2::Const::HTTP_NOT_IMPLEMENTED
        unless $handler_class->can($method);
    return $handler_class->$method($r, $resource);
}

Now you just need to implement Resource::* classes with your resource logic (including how to format representations), and Handler::* classes with methods named GET, HEAD, POST, etc and have them use $r and $resource to handle the requests.

For every new resource you need, you add one line of configuration, implement one Handler class (which I've found can often be an almost empty module inheriting from a generic base class), and implement one Resource class which contains the bulk of the code. I've also found that I often need to create one resource object in the context of handling a request for another resource; that's why my resource constructors take a separate argument for the uri instead of just getting the uri from $r. If I'm in Resource::Foo and I need a Resource::Bar object, I can say my $bar = Resource::Bar->new($r, '/bars/1234'); which creates the Bar object using the same URI that a client would use.



来源:https://stackoverflow.com/questions/1040393/perl-rest-flow-layout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!