4

我们试图让我们的 REST API 更友好一点,我们有一个 REST API 的基类,它继承自 Catalyst::Controller::REST。每个 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

4 回答 4

1

我想你想要LocalRegex而不是Regex. 但是为什么要使用正则表达式,而不仅仅是简单的Local

于 2009-02-26T22:06:19.320 回答
1

看起来,这取决于你想让你的应用程序有多优雅。您可以尝试使用链式操作,将 doc 操作链接到您想要附加 '/doc' 的每个操作。AFAIK,催化剂不支持将一个动作链接到多个其他动作,但这可能已经改变。或者,他们不能都接受一个额外的论点吗?

或者,修改上面的代码:

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

不过,这确实可能是不好的做法……

于 2009-06-23T16:31:54.913 回答
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 ) ;
   }
 }
于 2014-04-11T00:03:38.710 回答
-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 等。

一种方法是在基本控制器中使用 sub auto : Private { } 来检查 $c->req->path 或 $c->req->args 的 doc 最后然后转发到相关的私人行动(如果存在)

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

(未经测试)。此外,您可能想要 $c->detach 而不是转发,不确定。

于 2009-02-26T22:13:43.810 回答