OVERVIEW
This tutorial will give you an introduction to how to use Mojolicious::Plugin::Swagger2.You can also check out <https://github.com/jhthorsen/swagger2/tree/master/t/blog> if you want to look at a complete example application.
Another resources is the blog post <http://thorsen.pm/perl/programming/2015/07/05/mojolicious-swagger2.html>, which includes reasons for why you want to use Swagger2.
TUTORIAL
Swagger specification
The input ``url'' to given as argument to the plugin need to point to a valid swagger <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md> document.Every operation must have ``operationId'' specified, so this plugin knows where to look for the controller and method. The naming convention is:
"operationId": "methodControllerOptions"
Example specification:
{ "swagger": "2.0", "basePath": "/api", "paths": { "/pets/{petId}": { "get": { "operationId": "showPetById", "parameters": [ ... ], "responses": { "200": { ... } } } } } }
Here the ``operationId'' contains the method ``show'' and the controller ``Pet''. The ``Pet'' controller will again expand to "MyApp::Controller::Pet" or "MyApp::Pet" or whatever ``namespaces'' in Mojolicious::Routes is set to. The ``options'' part (ById) is simply ignored.
Note that ``showPetById'' and ``listPets'' will both result in looking for the ``Pet'' controller, since the plural ending (``s'') is removed.
The table below try to illustrate how the controller/method is resolved:
.---------------------------------------------------------------. | operationId | Controller | Method | Ignored | |------------------------|--------------|-------------|---------| | childrenOfPerson | Person | children | Of | | designByUser | User | design | By | | fooWithBar | Bar | foo | With | | getPetById | Pet | get | ById | | listUsers | User | list | s | | peopleInConversation | Conversation | people | In | | searchForPets | Pet | search | For, s | | sendToConversation | Conversation | send | To | | createFileInFileSystem | FileSystem | create_file | In | | removeFromFileSystem | FileSystem | remove | From | '---------------------------------------------------------------'
The operationId rules will be updated if bugs or incompatibility is discovered.
Application
The application need to load the Mojolicious::Plugin::Swagger2 plugin, with a URL to the API specification. The plugin will then add all the routes defined in the ``Swagger specification''.
package MyApp; use Mojo::Base "Mojolicious"; sub startup { my $app = shift; $app->plugin(Swagger2 => { url => app->home->rel_file("api.json") }); }
Controller
The method names defined in the controller will be a decamelized version of "operationId".The example ``Swagger specification'' above, will result in "show()" in the controller below to be called. This method will receive the current Mojolicious::Controller object, input arguments and a callback. The callback should be called with a HTTP status code, and a data structure which will be validated and serialized back to the user agent.
$args (input arguments) will be a hash, where the keys match ``name'' in the ``parameters'' defined in the Swagger spec, and the values are whatever input came from the client. This also goes for the ``body'' parameter: This means that the input JSON from HTTP body will not be flattened, but stored under the body parameter name in $args.
package MyApp::Controller::Pet; sub show { my ($c, $args, $cb) = @_; # Example $args: # $args->{body_param_name} == $c->req->json # $args->{query_param_name} == $c->req->url->query->param("query_param_name") # $args->{"X-Header-Name"} == $c->req->headers->header("X-Header-Name") $c->$cb({limit => 123}, 200); }