—=head1 NAME
Swagger2::Guides::Tutorial - Tutorial for Mojolicious::Plugin::Swagger2
=head1 OVERVIEW
This tutorial will give you an introduction to how to use
L<Mojolicious::Plugin::Swagger2>.
You can also check out L<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
which includes reasons for why you want to use L<Swagger2>.
=head1 TUTORIAL
=head2 Swagger specification
The input L</url> to given as argument to the plugin need to point to a
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 C<MyApp::Controller::Pet> or
C<MyApp::Pet> or whatever L<Mojolicious::Routes/namespaces> 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 I<if> bugs or incompatibility is
discovered.
=head2 Application
The application need to load the L<Mojolicious::Plugin::Swagger2> plugin,
with a URL to the API specification. The plugin will then add all the routes
defined in the L</Swagger specification>.
package MyApp;
use Mojo::Base "Mojolicious";
sub startup {
my $app = shift;
$app->plugin(Swagger2 => { url => app->home->rel_file("api.json") });
}
=head2 Controller
The method names defined in the controller will be a
L<decamelized|Mojo::Util::decamelize> version of C<operationId>.
The example L</Swagger specification> above, will result in C<show()> in the
controller below to be called. This method will receive the current
L<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.
C<$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 C<$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);
}
=head1 SEE ALSO
=over 4
=item * L<Swagger2::Guides::ProtectedApi> - Protected API Guide
=back
=head1 AUTHOR
Jan Henning Thorsen - C<jhthorsen@cpan.org>
=cut