Mojolicious::Plugin::OpenAPI::Guides::Tutorial - Mojolicious <3 Open API (Swagger)
This guide will give you an introduction to how to use Mojolicious::Plugin::OpenAPI.
You can also have a look at http://thorsen.pm/perl/programming/2015/07/05/mojolicious-swagger2.html, which includes reasons for why you want to use Open API - also known as Swagger.
This plugin reads an OpenAPI specification and generate routes and input/output rules from it. See JSON::Validator for supported schema file formats.
{ "basePath": "/api", "paths": { "/pets": { "get": { "x-mojo-to": "pet#list", "summary": "Finds pets in the system", "parameters": [ {"in": "body", "name": "body", "schema": {"type": "object"}}, {"in": "query", "name": "age", "type": "integer"}} ], "responses": { "200": { "description": "Pet response", "schema": { "type": "array", "items": { "type": "object" } } }, "default": { "description": "Unexpected error", "schema": { "$ref": "http://git.io/vcKD4#" } } } } } } }
The complete HTTP request for getting the "pet list" will be GET /api/pets The first part of the path ("/api") comes from basePath, the second part comes from the key under paths, and the HTTP method comes from the key under /pets.
GET /api/pets
basePath
paths
/pets
parameters and responses will be used to define rules for input and output. Continue reading for explanation about "x-mojo-to".
parameters
responses
The non-standard part in the spec above is "x-mojo-to". The "x-mojo-to" key can be either a plain string, object (hash) or an array. The string and hash will be passed directly to "to" in Mojolicious::Routes::Route, while the array ref will be flatten. Examples:
"x-mojo-to": "pet#list" $route->to("pet#list"); "x-mojo-to": {"controller": "pet", "action": "list", "foo": 123} $route->to({controller => "pet", action => "list", foo => 123); "x-mojo-to": ["pet#list", {"foo": 123}] $route->to("pet#list", {foo => 123});
"x-mojo-name" is also a non-standard key, which will either find an existing route (useful for Mojolicious::Lite apps) or name the route which is generated. The default value used is "operationId" (see the specification), unless "x-mojo-name" is specified.
package Myapp; use Mojolicious; sub startup { my $app = shift; $app->plugin("OpenAPI" => {url => $app->home->rel_file("myapi.json")}); }
The first thing in your code that you need to do is to load this plugin and the "Specification". See "register" in Mojolicious::Plugin::OpenAPI for information about what the plugin config can be.
See also "SYNOPSIS" in Mojolicious::Plugin::OpenAPI for example Mojolicious::Lite application.
package Myapp::Controller::Pet; sub list { my $c = shift; # Do not continue on invalid input and render a default 400 # error document. return if $c->openapi->invalid_input; # You might want to introspect the specification for the current route my $spec = $c->openapi->spec; unless ($spec->{'x-opening-hour'} == (localtime)[2]) { return $c->reply->openapi([], 498); } # $c->openapi->invalid_input copies valid data to validation object, # and the normal Mojolicious api works as well. my $input = $c->validation->output; my $age = $c->param("age"); # same as $input->{age} my $body = $c->req->json; # same as $input->{body} # $output will be validated by the OpenAPI spec before rendered my $output = {pets => [{name => "kit-e-cat"}]}; $c->reply->openapi(200 => $output); }
The input will be validated using "openapi.invalid_input" in Mojolicious::Plugin::OpenAPI while the output is validated through "reply.openapi" in Mojolicious::Plugin::OpenAPI.
The default error document rendered on invalid input and output looks like this:
{ "errors": [ {"path": "/some/json/path", "message": "Some error message"}, {"path": "/age", "message": "Expected integer - got string."} ] }
The "errors" key will contain one element for all the invalid data, and not just the first one. The useful part for a client is mostly the "path", while the "message" is just to add some human readable debug information for why this request/response failed.
The HTTP status code on invalid input is 400, and 500 for invalid output
Rendering binary data such as images can be accomplished by creating a Mojo::Asset object and pass it on to "reply.openapi" in Mojolicious::Plugin::OpenAPI, like this:
sub get_image { my $c = shift->openapi->valid_input or return; my $asset = Mojo::Asset::File->new(path => "image.jpeg"); $c->reply->openapi(200 => $asset); }
The example above will try to guess the "Content-Type" by looking at the extension of "path" in Mojo::Asset::File and default to "application/octet-stream" if the extension is unknown. If you want to specify another content type, then simple define it up front:
sub get_text { my $c = shift->openapi->valid_input or return; my $asset = Mojo::Asset::Memory->new; $asset->add_chunk("some data"); $c->res->headers->content_type("text/plain"); $c->reply->openapi(200 => $asset); }
Mojolicious::Plugin::OpenAPI, https://openapis.org/specification.
To install Mojolicious::Plugin::OpenAPI, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Mojolicious::Plugin::OpenAPI
CPAN shell
perl -MCPAN -e shell install Mojolicious::Plugin::OpenAPI
For more information on module installation, please visit the detailed CPAN module installation guide.