|
NAMEMojolicious::Plugin::OpenAPI::Guides::OpenAPIv3 - Mojolicious <3 OpenAPI v3 OVERVIEWThis guide will give you an introduction on how to use Mojolicious::Plugin::OpenAPI with OpenAPI version v3.x. TUTORIALSpecificationThis plugin reads an OpenAPI specification <https://openapis.org/specification> and generates routes and input/output rules from it. See JSON::Validator for supported schema file formats. {
"openapi": "3.0.2",
"info": {
"version": "1.0",
"title": "Some awesome API"
},
"paths": {
"/pets": {
"get": {
"operationId": "getPets",
"x-mojo-name": "get_pets",
"x-mojo-to": "pet#list",
"summary": "Finds pets in the system",
"parameters": [
{
"in": "query",
"name": "age",
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "Pet response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"pets": {
"type": "array",
"items": {
"type": "object"
}
}
}
}
}
}
}
}
}
}
},
"servers": [
{
"url": "/api"
}
]
}
The complete HTTP request for getting the "pet list" will be "GET /api/pets" The first part of the path ("/api") comes from "servers", the second part comes from the keys under "paths", and the HTTP method comes from the keys under "/pets". The different parts of the specification can also be retrieved as JSON using the "OPTIONS" HTTP method. Example: OPTIONS /api/pets OPTIONS /api/pets?method=get Note that the use of "OPTIONS" is EXPERIMENTAL, and subject to change. Here are some more details about the different keys:
References with files Only a file reference like "$ref": "my-other-cool-component.json#/components/schemas/inputSchema" Is supported, though a valid path must be used for both the reference and in the referenced file, in order to produce a valid spec output. See "File references" in Known Issues for unsupported file references Application package Myapp;
use Mojo::Base "Mojolicious";
sub startup {
my $app = shift;
$app->plugin("OpenAPI" => {url => $app->home->rel_file("myapi.json")});
}
1;
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. Controller package Myapp::Controller::Pet;
use Mojo::Base "Mojolicious::Controller";
sub list {
# Do not continue on invalid input and render a default 400
# error document.
my $c = shift->openapi->valid_input or return;
# 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->render(openapi => [], status => 498);
}
my $age = $c->param("age");
my $body = $c->req->json;
# $output will be validated by the OpenAPI spec before rendered
my $output = {pets => [{name => "kit-e-cat"}]};
$c->render(openapi => $output);
}
1;
The input will be validated using "openapi.valid_input" in Mojolicious::Plugin::OpenAPI while the output is validated through then openapi handler. Route namesRoutes will get its name from either "x-mojo-name" or from "operationId" if defined in the specification. The route name can also be used the other way around, to find already defined routes. This is especially useful for Mojolicious::Lite apps. Note that if spec_route_name is used then all the route names will have that value as prefix: spec_route_name = "my_cool_api" operationId or x-mojo-name = "Foo" Route name = "my_cool_api.Foo" You can also set "x-mojo-name" in the spec, instead of passing spec_route_name to plugin(): {
"openapi": "3.0.2",
"info": { "version": "1.0", "title": "Some awesome API" },
"x-mojo-name": "my_cool_api"
}
Default response schemaA default response definition will be added to the API spec, unless it's already defined. This schema will at least be used for invalid input (400 - Bad Request) and invalid output (500 - Internal Server Error), but can also be used in other cases. See "default_response_codes" in Mojolicious::Plugin::OpenAPI and "default_response_name" in Mojolicious::Plugin::OpenAPI for more details on how to configure these settings. The response schema will be added to your spec like this, unless already defined: {
...
"components": {
...
"schemas": {
...
"DefaultResponse": {
"type": "object",
"required": ["errors"],
"properties": {
"errors": {
"type": "array",
"items": {
"type": "object",
"required": ["message"],
"properties": {"message": {"type": "string"}, "path": {"type": "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. Rendering binary dataRendering assets and binary data should be accomplished by using the standard Mojolicious tools: sub get_image {
my $c = shift->openapi->valid_input or return;
my $asset = Mojo::Asset::File->new(path => "image.jpeg");
$c->res->headers->content_type("image/jpeg");
$c->reply->asset($asset);
}
OpenAPIv2 to OpenAPIv3 conversionBoth online and offline tools are available. One example is of this is <https://github.com/mermade/openapi-webconverter> Known issuesFile referencesRelative file references like the following "$ref": "my-cool-component.json#" "$ref": "my-cool-component.json" Will also be placed under '#/definitions/...', again producing a spec output which will not pass validation. SEE ALSOMojolicious::Plugin::OpenAPI, <https://openapis.org/specification>.
|