Can't call method "validator" on an undefined value
Ovid opened this issue · comments
I'm trying to take the Mojolicious:Lite 'echo' example from the docs and play around with turning that into a well-structured mojo app, but I'm getting the following error:
Can't call method "validator" on an undefined value at .../Mojolicious/Plugin/OpenAPI.pm line 200.
I've stripped out all other code to reduce this to a minimal use case.
My main class:
package My::Example;
use Mojo::Base 'Mojolicious', -signatures;
sub startup ($app) {
$app->plugin( OpenAPI => { url => $app->home->rel_file('data/openapi.yaml') } );
my $r = $app->routes;
$r->post('/echo')->to('echo#echo');
$app->secrets( ['Shut up, Mojo'] );
$app->start;
}
1;
My controller class:
package My::Example::Controller::Echo;
use Mojo::Base 'Mojolicious::Controller', -signatures;
sub echo ($self) {
$self = $self->app->openapi->valid_input or return;
# XXX the line above is where we blow up
# generate some data
my $data = { body => $self->req->json };
$self->render( openapi => $data );
}
1;
My OpenAPI spec:
swagger: 2.0
basePath: /api
schemes:
- http
info:
title: Quizzes
version: 1.0
paths:
/echo:
post:
operationId: echo
parameters:
- in: body
name: body
schema:
type: object
responses:
200:
description: Echo response
schema:
type: object
And the test that is generating the error:
#!/usr/bin/env perl
use Test::Mojo;
use Test::More;
my $t = Test::Mojo->new('My::Example');
# Post a JSON document
$t->post_ok(
'/echo' => json => { event => 'full moon' },
'We can send echo dasta'
) #
->status_is( 200, '... and get an OK status' ) #
->json_is(
'/body' => { event => 'full moon' },
'... the data should be in the body'
) #
->header_is(
'Content-Type',
'application/json;charset=UTF-8',
'... and it should be a JSON content-type'
); #
done_testing;
That test worked fine when I was using a Lite app. I've searched like mad all through the docs and even tests to figure out what I'm doing wrong, but to no avail. Help?
- Perl v5.26.3
- Mojolicious version 9.22
- Mojolicious::Plugin::OpenAPI version 5.02
Note that I have a basePath: /api
in the spec, even though my test calls /echo
.
Changing that to /api/echo
in the test gets me:
t/basic.t .. [2022-03-12 15:00:12.65159] [10099] [trace] [Txd4wWPlecBL] POST "/api/echo"
[2022-03-12 15:00:12.65195] [10099] [trace] [Txd4wWPlecBL] Template "echo.html.ep" not found
[2022-03-12 15:00:12.65244] [10099] [error] [Txd4wWPlecBL] Route without action and nothing to render at /Users/ovid/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojolicious.pm line 125.
[2022-03-12 15:00:12.65269] [10099] [trace] [Txd4wWPlecBL] 500 Internal Server Error (0.001104s, 905.797/s)
I've also tried changing my main class:
# $r->post('/echo')->to('echo#echo');
$r->post('/api/echo')->to('echo#echo');
But I get the same error (but since I have a basePath:
, it wasn't actually necessary to do that in the Lite app). There seems to be very little documentation about using this plugin with a full Mojo app.
If I remove the basePath: /api
from the config, I get the "Route without action" error.
This is incorrect:
$self->app->openapi->valid_input
it should be:
$self->openapi->valid_input
The helper can’t be called on the app, since you can load the plugin multiple times, allowing each route work on a different spec and a different validator instance.
@jhthorsen: Thank you for that explanation. It's very clear.
Unfortunately, I get the same error with $self->openapi->valid_input
.
When I look at your code closer I find more issues, but it boils down to the helpers not being called inside an OpenAPI powered action.
The SYNOPSIS is too simple and it has created so much confusion for users that I consider getting rid of it. Please read one of the following (or both) documents instead:
- https://metacpan.org/dist/Mojolicious-Plugin-OpenAPI/view/lib/Mojolicious/Plugin/OpenAPI/Guides/OpenAPIv2.pod
- https://metacpan.org/dist/Mojolicious-Plugin-OpenAPI/view/lib/Mojolicious/Plugin/OpenAPI/Guides/OpenAPIv3.pod
Just to give you some pointers: (They are documented in the guides above)
- Your API spec defines a route "POST /api/echo"
- Your test does not send a request to that route. It sends it to "/echo".
- The action "echo#echo" is not known to the OpenAPI plugin, since there's no identifier that connects the spec and the Perl code. You need either a route name and a matching operationId or "x-mojo-to" (Highly recommended!)
Feel free to hang around in #perl-openapi and I'll try to guide you if you have further questions after reading the guides, but because of the timezone I might not be available right away.
I tried to make it a bit more clear in the documentation now that you should read the guides: https://metacpan.org/release/JHTHORSEN/Mojolicious-Plugin-OpenAPI-5.04/view/lib/Mojolicious/Plugin/OpenAPI.pm#SYNOPSIS