The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Swagger2::Guides::Tutorial - Tutorial for Mojolicious::Plugin::Swagger2

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 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);
  }

SEE ALSO

AUTHOR

Jan Henning Thorsen - jhthorsen@cpan.org