Как добавить / doc / в конец каждого URL-адреса в Catalyst? - PullRequest
4 голосов
/ 26 февраля 2009

Мы пытаемся сделать наш REST API более дружественным, у нас есть базовый класс для нашего REST API, который наследуется от Catalyst :: Controller :: REST. Каждый класс REST может идентифицировать параметры запроса, которые он принимает. Мы подумали, что было бы неплохо сделать эту информацию общедоступной и поместить ее в базовый класс:

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

И оттуда к каждому URL REST можно добавить / 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" отправляется через франшизу, даже если контроллером для данного URL-адреса будет API :: V1 :: Version или что-то в этом роде.

Как я могу обойти это? Очевидно, LocalRegex не работает, и цепные действия не кажутся подходящими, потому что из-за природы нашего приложения мы никогда не знаем, сколько частей пути будет между '/ api / v1 /' и '/ doc /'.

Чего мне не хватает?

Ответы [ 4 ]

1 голос
/ 23 июня 2009

Кажется, все зависит от того, насколько элегантно вы хотите сделать свое приложение. Вы можете попробовать что-то с цепочечными действиями, связывая действие документа с каждым действием, к которому вы хотите добавить «/ doc». AFAIK, катализатор не поддерживает связывание действия с несколькими другими действиями, но это могло измениться. Или же, не могли бы они все принять один дополнительный аргумент?

Или, изменив код выше:

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

Это действительно плохая практика, хотя ...

1 голос
/ 27 февраля 2009

Я думаю, что вы хотите LocalRegex вместо Regex. Но почему регулярное выражение вообще, а не просто Local?

0 голосов
/ 11 апреля 2014

Вы можете сделать этот корневой файл сайта (Hello.pm в папке lib, если сайт называется Hello). Вы можете использовать метод prepare_path и проверить, является ли первая часть api / v1, чтобы добавить часть документа в конец. Не уверен, что делать это на этом этапе - плохая практика.

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 ) ;
   }
 }
0 голосов
/ 27 февраля 2009

Я думаю, что 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, а не вперед, не уверен.

...