如何将/ doc /添加到Catalyst中每个URL的末尾?

时间:2009-02-26 15:18:35

标签: perl catalyst

我们正在尝试使我们的REST API更友好,我们有一个继承自Catalyst :: Controller :: REST的REST API的基类。每个REST类都可以识别它接受的查询参数。我们认为将这些信息公开并将其放入基类会很好:

sub doc : Regex('/doc$') {
    my ( $self, $c ) = @_;
    $c->stash->{params} = $c->forward('allowed_query_params');
}

从那里开始,每个REST URL都可以在末尾添加/ doc /以显示它接受的查询参数。

它不起作用。 $ self总是一个PIPs :: C :: API :: V1 :: Franchise实例,无论调用哪个URL。这似乎是因为:

[26 Feb 2009 15:07:40,509] [Catalyst.Dispatcher] [DEBUG] Loaded Private actions:
.-----------------------+--------------------------------------+--------------.
| Private               | Class                                | Method       |
+-----------------------+--------------------------------------+--------------+
...
| /api/v1/franchise/doc | PIPs::C::Api::V1::Franchise          | doc          |

[26 Feb 2009 15:07:40,514] [Catalyst.DispatchType.Regex] [DEBUG] Loaded Regex actions:
.--------------------------------------+--------------------------------------.
| Regex                                | Private                              |
+--------------------------------------+--------------------------------------+
| /doc$                                | /api/v1/franchise/doc                |
| /doc$                                | /api/v1/version/doc                  |
| /doc$                                | /api/v1/creditrole/doc               |
| /doc$                                | /api/v1/doc                          |
| /doc$                                | /api/v1/segmentevent/doc             |
| /doc$                                | /api/v1/collection/doc               |
| /doc$                                | /api/v1/episode/doc                  |

因此,“doc”方法的第一个实例通过Franchise进行调度,即使给定URL的控制器是API :: V1 :: Version或类似的东西。

我该如何解决这个问题?显然,LocalRegex不起作用,链式动作似乎不合适,因为由于我们的应用程序的性质,我们永远不知道'/ api / v1 /'和'/ doc /'之间有多少路径部分。

我错过了什么?

4 个答案:

答案 0 :(得分:1)

我认为你想要LocalRegex而不是Regex。但是为什么要使用正则表达式,而不仅仅是普通Local

答案 1 :(得分:1)

这取决于你想要制作应用程序的优雅程度。您可以尝试使用链式操作,将doc操作链接到您要追加'/ doc'的每个操作。 AFAIK,催化剂不支持将动作链接到多个其他动作,但可能已经改变。 或者,他们不是都可以再提出一个论点吗?

或者,修改上面的代码:

sub auto : Private {
    my ($self, $c) = @_;
    if ((my $path = $c->req->path) =~ /\/doc$/) {
        $path =~ s/\/doc//;
        $c->detach($path);
    }
}

这可能是糟糕的做法,但是......

答案 2 :(得分:0)

您可以执行此根站点文件(如果站点名为Hello,则在lib文件夹中为Hello.pm)。您可以使用方法prepare_path并检查第一部分是否为api / v1以将doc部分附加到末尾。不确定在这个阶段做这件事是不好的做法。

sub prepare_path {
   my $c = shift;

   $c->maybe::next::method( @_ ) ;

   # Get the path
   my $path = $c->request->path;

   if ((index($path, 'api/v1') > 0)) {
      $path .= '/doc';

      # Change the path
      $c->request->path( $path ) ;
   }
 }

答案 3 :(得分:-1)

我认为Local无法正常工作,因为控制器操作可能会接受多个参数,因此Controller :: Foo :: my_action最终可能会接受:/ foo / my_action / this / 1 / that / 2 / the_other

所以,如果我正确地读你,你想要/ foo / my_action / this / 1 / that / 2 / the_other / doc, / bar / other_action / thing / 4 / thang / 2 / the_other / doc等。

这样做的一种方法是在基本控制器中有一个子auto:Private {},用于检查$ c-> req-> path或$ c-> req-> args for doc at结束,然后转发相关的私人诉讼,如果它在那里

sub auto : Private {
    my ($self, $c) = @_;
    $c->forward('doc_method) if $c->req->args->[ $@{$c->req->args}  eq 'doc';
}

(未测试)。你可能想要$ c->分离而不是前进,不确定。