jhthorsen / mojolicious-plugin-openapi

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

How can I add more definitions and paths to my application API from a Mojo plugin? #229

Closed kberov closed 2 years ago

kberov commented 2 years ago

Hello all, Did you have the following problem to solve? If yes, please advise. I have an existing Mojolicious application with already defined api.json file. I create a new plugin for the application (e.g. a shopping cart). I want to add new routes/paths and definitions to my existing OpenAPI. I tried rudely in my plugin's register() method the following:

    %{$app->openapi->spec->{definitions}} = (%{$app->openapi->spec->{definitions}},$self->_definitions);
   # then I planed to add the paths too

This happens after I have already loaded the OpenAPI plugin. My plugin loads after it and tries to use it to enrich the application REST API with the new functionality.

but when I try to load the api to see if my new definitions are in place I get an error (and rightfully because my definition is not in the main api-v1.0.json):


[2022-01-01 23:16:01.26755] [34038] [error] [zmicmOB-o_xS] Unable to resolve "#definitions/OrderProduct" from "file:///home/berov/opt/dev/Slovo/lib/Slovo/resources/api-v1.0.json". (schema/base_url) 
[2022-01-01 23:16:01.26755] [34038] [error] [zmicmOB-o_xS] Unable to resolve "#definitions/OrderProduct" from "file:///home/berov/opt/dev/Slovo/lib/Slovo/resources/api-v1.0.json". (schema/base_url) at /home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/JSON/Validator/Store.pm line 95.

[2022-01-01 23:16:01.26788] [34038] [warn] OpenAPI >>> GET /api [{"message":"Internal Server Error.","path":"\/"}]
[2022-01-01 23:16:01.26815] [34038] [trace] [zmicmOB-o_xS] 500 Internal Server Error (0.005477s, 182.582/s)
at /home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/JSON/Validator/Store.pm line 95.

[2022-01-01 23:16:01.26788] [34038] [warn] OpenAPI >>> GET /api [{"message":"Internal Server Error.","path":"\/"}]
[2022-01-01 23:16:01.26815] [34038] [trace] [zmicmOB-o_xS] 500 Internal Server Error (0.005477s, 182.582/s)

So, How can I add more definitions and paths to my application API from a Mojo plugin? Thanks!

kberov commented 2 years ago

I found a mistake in my reference. I should have written "#/definitions/OrderProduct" instead of "#definitions/OrderProduct". I also changed my code to load and register the plugin again in my Mojo plugin after merging the structure.

  my $spec = Storable::dclone $app->openapi->spec;
  %{$spec->{definitions}} =(%{$spec->{definitions}},$self->_definitions);
  %{$spec->{paths}} =(%{$spec->{paths}},$self->_paths);
  $app->plugin(OpenAPI => { spec => $spec });

If I have another plugin, that wants to enrich the REST API with its own paths and definitions for my application, I will have to do the same and so on. Now my question is rather, "Is this a good way or there is a more elegant way to build up my REST API out of Mojo plugins functionalities?"

jhthorsen commented 2 years ago

The way to do it is to read the json/yaml file, change the data structure and then at last load the plugin with the modified structure.

Neither the plugin nor JSON::Validator supports changing the spec after it is resolved, which happens when you load the plugin. You might be able to add do some tricks if the specification does not include any $ref, but as soon as there is one, it won’t work.

jhthorsen commented 2 years ago

Something like this:

my $spec = Mojo::JSON::decode_json($json_file->slurp);
# modify the spec
$app->plugin(spec => $spec);
kberov commented 2 years ago

@jhthorsen, Thanks! Yes I found that the last loading plugin (which wants to add routes or defs to the REST API) has to collect all the API files together, merge the pieces appropriately and call the OpenAPI's register() $app->plugin(OpenAPI => { spec => $spec });.