'Under' controller method called multiple times

46 views
Skip to first unread message

Justin Hawkins

unread,
Jun 13, 2019, 2:09:43 AM6/13/19
to mojol...@googlegroups.com
Hello all,

I think there is a good chance this is a case of “holding it wrong”, so I will first explain what I’m trying to achieve.

Standard web app, multiple ways of establishing rights to privileged routes.

The first is standard username/password, establishing a session.

The second is via an API key (supplied with a header).

I use two separate controller methods, one to check the session, one to check the header. Each one has the opportunity to set a stash variable indicating that the user has a valid session (via either cookie session or API key).

So I use two “under” routes to call each method. So far so good, things work ok.

The problem I have is that I later have another under route, to establish a new URL path for my REST interface.

Any requests that go through routes derived from that third “under" have a strange behaviour - they call the second ‘under’ controller twice!

This is probably easiest to see with an example:

package TestUnder;
use Mojo::Base 'Mojolicious';

# This method will run once at server start
sub startup {
  my $self = shift;

  # Load configuration from hash returned by config file
  my $config = $self->plugin('Config');

  # Configure the application
  $self->secrets($config->{secrets});

  # Router
  my $r = $self->routes;

  # All requests should go through these two
  $r = $r->under()->to('example#under_one');
  $r = $r->under()->to('example#under_two');
  $r->get('/')->to('example#welcome');

  # REST interface
  my $rest_v1 = $r->under('/rest/v1');
  $rest_v1->get('/')->to('example#welcome');

}

package TestUnder::Controller::Example;

use Mojo::Base 'Mojolicious::Controller';

sub under_one {
  my $self = shift;
  $self->app->log->info("under_one called");
  1;
}

sub under_two {
  my $self = shift;
  $self->app->log->info("under_two called");
  1;
}

sub welcome {
  my $self = shift;
  $self->render(text => 'hi');
}

1;

Example below - you can easily see that for the “REST” route, ‘under_two’ is called twice:
                                                                                                                                                                                                                                                                
$ script/test_under get / >/dev/null
[2019-06-13 15:28:30.55547] [44306] [debug] GET "/" (9ca39c7c)
[2019-06-13 15:28:30.55627] [44306] [debug] Routing to controller "TestUnder::Controller::Example" and action "under_one"
[2019-06-13 15:28:30.55637] [44306] [info] under_one called
[2019-06-13 15:28:30.55651] [44306] [debug] Routing to controller "TestUnder::Controller::Example" and action "under_two"
[2019-06-13 15:28:30.55661] [44306] [info] under_two called
[2019-06-13 15:28:30.55675] [44306] [debug] Routing to controller "TestUnder::Controller::Example" and action "welcome"
[2019-06-13 15:28:30.55704] [44306] [debug] 200 OK (0.001571s, 636.537/s)

$ script/test_under get /rest/v1 >/dev/null
[2019-06-13 15:28:34.95883] [44315] [debug] GET "/rest/v1" (6aad1c75)
[2019-06-13 15:28:34.95975] [44315] [debug] Routing to controller "TestUnder::Controller::Example" and action "under_one"
[2019-06-13 15:28:34.95984] [44315] [info] under_one called
[2019-06-13 15:28:34.95997] [44315] [debug] Routing to controller "TestUnder::Controller::Example" and action "under_two"
[2019-06-13 15:28:34.96005] [44315] [info] under_two called
[2019-06-13 15:28:34.96020] [44315] [debug] Routing to controller "TestUnder::Controller::Example" and action "under_two"
[2019-06-13 15:28:34.96031] [44315] [info] under_two called
[2019-06-13 15:28:34.96044] [44315] [debug] Routing to controller "TestUnder::Controller::Example" and action "welcome"
[2019-06-13 15:28:34.96083] [44315] [debug] 200 OK (0.001985s, 503.778/s)

$ mojo version
CORE
  Perl        (v5.26.1, darwin)
  Mojolicious (8.17, Supervillain)

OPTIONAL
  Cpanel::JSON::XS 4.04+  (n/a)
  EV 4.0+                 (n/a)
  IO::Socket::Socks 0.64+ (n/a)
  IO::Socket::SSL 2.009+  (2.051)
  Net::DNS::Native 0.15+  (n/a)
  Role::Tiny 2.000001+    (2.000005)

This version is up to date, have fun!

Regards,

Justin

Stefan Adams

unread,
Jun 14, 2019, 11:10:48 AM6/14/19
to mojolicious
I don't have an explanation for why this seems to be necessary for your situation, but after reading Mojolicious::Guides::Routing#Under, I found that this should work for you:

  # REST interface
  my $rest_v1 = $r->under('/rest/v1' => sub{1});

  $rest_v1->get('/')->to('example#welcome');
--
You received this message because you are subscribed to the Google Groups "Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mojolicious...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/mojolicious/8EB007C9-0631-448B-B654-56C6D1EE0A5A%40hawkins.id.au.

Dan Book

unread,
Jun 14, 2019, 11:32:17 AM6/14/19
to mojol...@googlegroups.com
The explanation is that each 'under' route is a discrete action from the endpoints, and must be defined and return 1 to continue the dispatch chain.

-Dan

Dan Book

unread,
Jun 14, 2019, 11:32:53 AM6/14/19
to mojol...@googlegroups.com
To just "establish a URL path", under is not needed, you can just use any which does not create a discrete action.

-Dan

Stefan Adams

unread,
Jun 14, 2019, 11:42:25 AM6/14/19
to mojolicious
On Fri, Jun 14, 2019 at 10:32 AM Dan Book <gri...@gmail.com> wrote:
To just "establish a URL path", under is not needed, you can just use any which does not create a discrete action.

Wow, I didn't realize you could use 'any' for this purpose!

It makes sense that 'under' must return 1 to continue the chain, but how is the Mojolicious::Lite example doing that?
# /foo
under '/foo';
Justin's full app example looks the same.

Thanks for your explanation, Dan!
 

Justin Hawkins

unread,
Jun 19, 2019, 3:47:52 AM6/19/19
to mojol...@googlegroups.com

> On 15 Jun 2019, at 01:02, Dan Book <gri...@gmail.com> wrote:
>
> To just "establish a URL path", under is not needed, you can just use any which does not create a discrete action.

Thanks Dan,

This worked perfectly.

The double call to the previous “under” is still a mystery but no longer a problem.

Cheers,

Justin
Reply all
Reply to author
Forward
0 new messages