Perl Mojolicious routes call sub only once

130 Views Asked by At

Iam using Mojolicious::Lite to declare routes for a webservice. Maybe i missunderstood the routes behaviour but if iam calling a subroutine in the routes definition it gets only called once.
I thougt the sub should get triggered every time the webservice route is called... which isn't the case.

For example i wrote a test route:

use Mojolicious::Lite;

get '/test' => {
    text => get_test()
};

sub get_test {
    say 'Hello iam only showing up once';

    return 'test';
};

This is the console output on starting the server and visiting the localhost:3000/test route:

Hello iam only showing up once
[2020-04-04 22:07:21.09011] [69050] [info] Listening at "http://*:3000"
Server available at http://127.0.0.1:3000
[2020-04-04 22:07:28.26033] [69050] [debug] [78278b87] GET "/test"
[2020-04-04 22:07:28.26097] [69050] [debug] [78278b87] 200 OK (0.000626s, 1597.444/s)

The "Hello iam only showing up once" is outputted once as the server starts. Visiting the route is not triggering the sub again.
If this is the wanted behaviour how can i get my routes to triggering the sub everytime the route is visited?

I need this because i use this webservice in my application to scan the network and return the result. And i want to rescan the network everytime i call the webservice GET route. Otherwise the data would be useless if its not up to date.

Thanks for your help and explanations.

2

There are 2 best solutions below

0
On BEST ANSWER

Your code isn't actually rendering. Your get sub needs to call the render method from Mojolicious::Controller. Inside the get sub, $_[0] is an instance of the controller. In a Mojolicious::Lite app, the route and controller are combined, so you do need to render. If you change your code to this, it will do what you might expect.

use Mojolicious::Lite;

get '/test' => sub {
    shift()->render(text => get_test());
};

sub get_test {
    warn "Hello I show up on every hit.\n";

    return 'test';
};

The key difference is the shift()->render(...) call, which could also be written like this:

get '/test' => sub {
    my $c = shift;
    $c->render(text => get_text());
}
0
On

The above answer is good, but one of the key problems in your code is that you seem to have incorrectly defined your route code ref:

get '/test' => {

should be:

get '/test' => sub {

This is why your get_test only gets called once - you are defining a hash and populating it with the result of get_test, instead of defining a subroutine. But see @DavidO's answer for the full detail on how to approach this.