我该如何在Perl中实现一个RESTful API?

13

我正在尝试在Perl中实现一个RESTful API。我的当前想法是通过正则表达式解析path_info,然后将请求分派到适当的子例程,该子例程将输出所请求资源的JSON、XML甚至XHTML。

例如,要检索有关用户1234的信息,RESTful客户端应在以下位置找到它:

http://example.com/model.pl/users/1234

以下是我第一次尝试实现RESTful API的框架代码:

model.pl:

#!/usr/bin/perl -w
use strict;
use CGI;

my $q = CGI->new();

print $q->header('text/html');

my $restfuluri  = $q->path_info;

if      ($restfuluri =~ /^\/(questions)\/([1-9]+$)/) { questions($1, $2); }
elsif   ($restfuluri =~ /^\/(users)\/([1-9]+$)/)     { users($1, $2); }


sub questions
{
      my $object = shift;
      my $value  = shift;

      #This is a stub, spits out JSON or XML when implemented.
      print $q->p("GET question : $object -> $value");
}

sub users
{
      my $object = shift;
      my $value  = shift;

      #This is a stub, spits out JSON or XML when implemented.
      print $q->p("GET user: $object -> $value");
}

在我继续之前,我想听听有经验的Perl黑客们的意见,看看我是否理解了基本思路,并且是否存在性能方面的严重缺陷。

我可以想象,过一段时间后,if/else代码块会变得非常庞大。

期待听取您的意见,让这段代码更加优秀。


3
我能建议一下吗?如果你的目标是构建一个RESTful API,那么你需要多花些时间去了解REST。RESTful接口并不仅仅是使用美观的URL来传递XML和JSON。 - Darrel Miller
请查看StackOverflow上其他详细解释REST的问题。 - aehlke
1
请别误解,我知道什么是REST,也了解REST的使用和滥用。我只需要一种快速而简单的方法为遗留应用程序提供RESTful API。它有一个完善的数据层,我所需要做的就是允许人们使用漂亮的URI以JSON或XML格式访问数据。我维护的东西必须比性感更可靠。在提问之前,我已经阅读了《RESTful Web services》O'Reilly书籍和Brian的大部分书籍。我认为这是一个合法的问题。此外,大多数讨论都涉及Ruby。谢谢。 - GeneQ
@Darrel Miller,不幸的是,我只需要做到这一点,而且没有更多:使用漂亮的URL来传递XML和JSON。谢谢。;-) - GeneQ
@GeneQ,漂亮的URI很好,RPC也很好,但是请不要在它不是REST时称其为REST。您对可靠性的看法也是错误的 - REST的重点是避免URI空间中脆弱的耦合,因此说您需要比“性感”更可靠的东西是不公平的。我没有读过那些书 - 如果您有兴趣,建议您阅读Fielding的论文以获取权威来源。 - aehlke
@GeneQ 我犯了一个错误。很难判断某人对REST的了解程度。只是出于好奇,为什么您需要API成为RESTful呢?仅使用Http上的简单XML数据有效载荷不足以满足您的需求吗?我假设您计划让客户端提前了解URL结构,并知道某些XML信息集将来自某些终端点,那么“RESTful” API为您提供了哪些好处呢? - Darrel Miller
8个回答

22
对于轻量级的REST API,我建议看一下Mojolicious。请求路由非常简单,内置的JSON渲染器和用户代理使得开发简单的REST API非常容易。如果你的应用程序相对较小,那么Mojo::Lite可能会满足你的需求。例如,你可以做这样的事情:
use Mojolicious::Lite;

get '/questions/(:question_id)' => sub {
    my $self = shift;
    my $result = {};
    # do stuff with $result based on $self->stash('question_id')
    return $self->render_json($result)
}

app->start;

9

我会使用类似CGI :: Application :: Dispatch的东西,它可以让我使用变量和REST方法构建调度表,并允许您使用来自CPAN的CGI和CGI :: Application模块。例如:

table => [
'/questions/:id[get]'    => { rm => 'get_question' },
'/users/:id[get]'        => { rm => 'get_user' }, # OR
':app/:id[post]'         => { rm => 'update' }, # where :app is your cgi application module
':app/:id[delete]'       => { rm => 'delete' },
],

(或者您可以使用auto_rest或auto_rest_lc)
您可以为每种类型的内容使用单独的CGI::Application类(或仅在cgi-app控制器类方法中使用类)。
CGI::Application还带有插件,可用于输出从模板生成的XML、JSON或文本。
cgi-app(和c::a::d)是CGI应用程序,并且可以在CGI、FastCGI或mod_perl下使用(几乎不需要更改)。C::A::D默认也是mod_perl PerlHandler。

1
简单的解决方案:
 use CGI;

 my $page  = new CGI;

 if( $ENV{ 'REQUEST_METHOD' } eq 'GET' ){

    my $data = <<json;
    {
    "isbn" : "123456",
    "title" : "Programming Perl",
    "author" : "L. Wall"
     }
 json

     print $page->header('application/json');

     print $data;
 }

由于您示例中的此处文档由于空格而无法工作,例如。 - Jinxed

1

为什么不使用已经实现的模块Apache2::REST? 它已经准备好了。


1

谢谢。但我会放弃。这并不是反对 Catalyst,只是为了提供一个(非常)传统的应用程序的 RESTful 接口。快速而简单的东西。;-) - GeneQ

0

我知道这个问题已经被问了很长时间,但我想提供一些更新的信息。

有一个非常有用的模块叫做Net::API::REST,可以在Apache2 mod_perl后面使用。

你只需要设置Apache,并创建自己的模块继承Net::API::REST,并创建一个init方法,在其中定义你的端点映射,例如:

sub init
{
    my $self = shift( @_ );
    $self->{routes} =
    {
    # e.g. your API version 1
    1 =>
        {
        'favicon.ico' => $self->curry::noop,
        auth =>
            {
            google =>
                {
                _handler => $self->curry::oauth_google,
                callback => $self->curry::oauth_google(callback => 1),
                },
            linkedin =>
                {
                _handler => $self->curry::oauth_linkedin,
                callback => $self->curry::oauth_linkedin(callback => 1),
                },
            },
        },
        stripe => $self->curry::stripe,
    };
    $self->{api_version} = 1;
    $self->{supported_api_versions} = [qw( 1 )];
    $self->{default_methods} = [qw( GET POST )];
    $self->{supported_methods} = [qw( DELETE GET HEAD OPTIONS POST PUT )];
    $self->{supported_languages} = [qw( en-GB en fr-FR fr ja-JP )];
    $self->SUPER::init( @_ );
    return( $self );
}

当有人访问您的端点之一时,相应的方法将在强大的环境中调用,以用于回复请求。请查看模块 metacpan 页面获取更多信息。


-1
简单的解决方案 - 通过对$data进行变量调整,使用qq~~;使所有代码保持对齐。
 use CGI;

 my $page  = new CGI;

 if( $ENV{ 'REQUEST_METHOD' } eq 'GET' ){

    my $data = qq~
        {
            "isbn" : "123456",
            "title" : "Programming Perl",
            "author" : "L. Wall"
        }
    ~;

     print $page->header('application/json');

     print $data;
 }

-3

如果你正在使用apache和mod_rewrite,为什么还要包含.pl文件呢?此外,你会丢失ID。你可以使用mod_rewrite重写URL,或者只需创建一个mod_perl处理程序并使用它来处理/dir/whatever。CGI::Application::Dispatch是一个mod_perl处理程序,可以执行rest。 - MkV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接