jhthorsen / mojolicious-plugin-openapi

OpenAPI / Swagger plugin for Mojolicious
53 stars 41 forks source link

RFE: Document interaction with routes #190

Closed jszinger closed 3 years ago

jszinger commented 3 years ago

The synopsis has the following code snippet:

post "/echo" => sub {
  my $c = shift->openapi->valid_input or return;
  my $data = {body => $c->req->json};
  $c->render(openapi => $data);
}, "echo";

plugin OpenAPI => {url => "data:///spec.json", schema => "v2"};

It works. Loading the plugin first doesn't work:

plugin OpenAPI => {url => "data:///spec.json", schema => "v2"};

post "/echo" => sub {
  my $c = shift->openapi->valid_input or return;
  my $data = {body => $c->req->json};
  $c->render(openapi => $data);
}, "echo";

I spent quite a bit of time trying to find the difference, and didn't find any documentation about this feature.

Now that I know about it the closest thing I see is in the Route Names section of Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3. "The route name can also be used the other way around, to find already defined routes. This is especially useful for Mojolicious::Lite apps." It is not obvious how it is useful. By searching the source, I think I found the implementation in Mojolicious::Plugin::OpenAPI::_add_routes.

The rules seem to be:

  1. Create a route with an arbitrary path and the desired name matching "x-mojo-name" or "operationId".

  2. Create paths in OpenAPI using "x-mojo-name" or "operationId" to match the route name. (I don't see any advantage to x-mojo-name.) Don't use "x-mojo-to".

  3. Load Mojolicious::Plugin::OpenAPI. It will automatically grab existing routes with matching names. Routes defined later are not affected.

  4. It works just as well in full as in Lite apps.

Please add a description of this feature to the docs.

jhthorsen commented 3 years ago

I'll look into it, but I highly suggest using M::P::OpenAPI with a full (not lite) app. I think that's much easier to work with.

jszinger commented 3 years ago

I am building a full app. For the full app the example MyApp::startup looks like

sub startup ($app) {
    my $r = $app->routes;
    # MyApp::Controller::Main::echo has the OpenAPI controller
    $r->get( '/echo')->to( 'main#echo')->name( 'echo');

    $app->plugin( 'Mojolicious::Plugin::OpenAPI' => {url => "data:///spec.json", schema => "v2"});
}

I am intrigued by the syntax in the synopsis, especially the ability to write an OpenAPI spec without any 'x-mojo' content—this avoids exposing implementation details to the API consumers. So I went ahead and tried it and finally figured out the rules I describe above. I'm hoping to help others avoid this suffering.

I also believe that it is important to clearly and fully explain the features used in the SYNOPSIS.

jhthorsen commented 3 years ago

this avoids exposing implementation details to the API consumers Many people have said this before you, but I don't share your concern. If you do find an alternative way, then please do let me know though.