1Mojolicious::Plugin::OpUesneArPIC:oM:noGtjuroiildbieucsti:eo:duOspP:ee:nrPAllPuIDgvoi3cn(u:3m:)eOnpteantAiPoIn::Guides::OpenAPIv3(3)
2
3
4

NAME

6       Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3 - Mojolicious <3
7       OpenAPI v3
8

OVERVIEW

10       This guide will give you an introduction on how to use
11       Mojolicious::Plugin::OpenAPI with OpenAPI version v3.x.
12

TUTORIAL

14   Specification
15       This plugin reads an OpenAPI specification
16       <https://openapis.org/specification> and generates routes and
17       input/output rules from it. See JSON::Validator for supported schema
18       file formats.
19
20         {
21           "openapi": "3.0.2",
22           "info": {
23             "version": "1.0",
24             "title": "Some awesome API"
25           },
26           "paths": {
27             "/pets": {
28               "get": {
29                 "operationId": "getPets",
30                 "x-mojo-name": "get_pets",
31                 "x-mojo-to": "pet#list",
32                 "summary": "Finds pets in the system",
33                 "parameters": [
34                   {
35                     "in": "query",
36                     "name": "age",
37                     "schema": {
38                       "type": "integer"
39                     }
40                   }
41                 ],
42                 "requestBody": {
43                   "content": {
44                     "application/json": {
45                       "schema": {
46                         "type": "object"
47                       }
48                     }
49                   }
50                 },
51                 "responses": {
52                   "200": {
53                     "description": "Pet response",
54                     "content": {
55                       "application/json": {
56                         "schema": {
57                           "type": "object",
58                           "properties": {
59                             "pets": {
60                               "type": "array",
61                               "items": {
62                                 "type": "object"
63                               }
64                             }
65                           }
66                         }
67                       }
68                     }
69                   }
70                 }
71               }
72             }
73           },
74           "servers": [
75             {
76               "url": "/api"
77             }
78           ]
79         }
80
81       The complete HTTP request for getting the "pet list" will be "GET
82       /api/pets" The first part of the path ("/api") comes from "servers",
83       the second part comes from the keys under "paths", and the HTTP method
84       comes from the keys under "/pets".
85
86       The different parts of the specification can also be retrieved as JSON
87       using the "OPTIONS" HTTP method. Example:
88
89         OPTIONS /api/pets
90         OPTIONS /api/pets?method=get
91
92       Note that the use of "OPTIONS" is EXPERIMENTAL, and subject to change.
93
94       Here are some more details about the different keys:
95
96       • openapi, info and paths
97
98         These three sections are required to make the specification valid.
99         Check out
100         <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md>
101         for a complete reference to the specification.
102
103       • parameters, requestBody and responses
104
105         "parameters", "requestBody" and "responses" will be used to define
106         input and output validation rules, which is used by "openapi.input"
107         in Mojolicious::Plugin::OpenAPI and when rendering the response back
108         to the client, using "render(openapi => ...)".
109
110         Here OpenAPIv3 input differs from the v2 spec, where "parameters" is
111         used for input in the path or query of the request. The "requestBody"
112         is used for input passed in the body.
113
114         Have a look at "RENDERER" in Mojolicious::Plugin::OpenAPI for more
115         details about output rendering.
116
117       • operationId and x-mojo-name
118
119         See "Route names".
120
121       • x-mojo-placeholder
122
123         "x-mojo-placeholder" can be used inside a parameter definition to
124         instruct Mojolicious to parse a path part in a certain way. Example:
125
126           "parameters": [
127             {
128               "x-mojo-placeholder": "#",
129               "in": "path",
130               "name": "email",
131               "type": "string"
132             }
133           ]
134
135         See Mojolicious::Guides::Routing for more information about
136         "standard", "relaxed" and "wildcard" placeholders. The default is to
137         use the "standard" ("/:foo") placeholder.
138
139       • x-mojo-to
140
141         The non-standard part in the spec above is "x-mojo-to". The "x-mojo-
142         to" key can be either a plain string, object (hash) or an array. The
143         string and hash will be passed directly to "to" in
144         Mojolicious::Routes::Route, while the array ref will be flattened.
145         Examples:
146
147           "x-mojo-to": "pet#list"
148           $route->to("pet#list");
149
150           "x-mojo-to": {"controller": "pet", "action": "list", "foo": 123}
151           $route->to({controller => "pet", action => "list", foo => 123);
152
153           "x-mojo-to": ["pet#list", {"foo": 123}, ["format": ["json"]]]
154           $route->to("pet#list", {foo => 123});
155           $route->pattern->constraints->{format} = ["json"];
156
157       • security and securitySchemes
158
159         The securityScheme is added under components, where one way is to
160         have the client place an apiKey in the header of the request
161
162           {
163             ...
164             "components": {
165               "securitySchemes": {
166                 "apiKey": {
167                   "name": "X-Api-Key",
168                   "in": "header",
169                   "type": "apiKey"
170                 }
171               }
172             }
173           }
174
175         It is then referenced under the path object as security like this
176
177           {
178             ...
179             "paths": {
180               "/pets": {
181                 "get": {
182                   "operationId": "getPets",
183                   ...
184                   "security": [
185                     {
186                       "apiKey": []
187                     }
188                   ]
189                 }
190               }
191             }
192           }
193
194         You can then utilize security, by adding a security callback when
195         loading the plugin
196
197           $self->plugin(
198             OpenAPI => {
199               spec     => $self->static->file("openapi.json")->path,
200               security => {
201                 apiKey => sub {
202                   my ($c, $definition, $scopes, $cb) = @_;
203                   if (my $key = $c->tx->req->content->headers->header('X-Api-Key')) {
204                     if (got_valid_api_key()) {
205                       return $c->$cb();
206                     }
207                     else {
208                       return $c->$cb('Api Key not valid');
209                     }
210                   }
211                   else {
212                     return $c->$cb('Api Key header not present');
213                   }
214                 }
215               }
216             }
217           );
218
219       References with files
220
221       Only a file reference like
222
223         "$ref": "my-other-cool-component.json#/components/schemas/inputSchema"
224
225       Is supported, though a valid path must be used for both the reference
226       and in the referenced file, in order to produce a valid spec output.
227
228       See "File references" in Known Issues for unsupported file references
229
230   Application
231         package Myapp;
232         use Mojo::Base "Mojolicious";
233
234         sub startup {
235           my $app = shift;
236           $app->plugin("OpenAPI" => {url => $app->home->rel_file("myapi.json")});
237         }
238
239         1;
240
241       The first thing in your code that you need to do is to load this plugin
242       and the "Specification". See "register" in Mojolicious::Plugin::OpenAPI
243       for information about what the plugin config can be.
244
245       See also "SYNOPSIS" in Mojolicious::Plugin::OpenAPI for example
246       Mojolicious::Lite application.
247
248   Controller
249         package Myapp::Controller::Pet;
250         use Mojo::Base "Mojolicious::Controller";
251
252         sub list {
253
254           # Do not continue on invalid input and render a default 400
255           # error document.
256           my $c = shift->openapi->valid_input or return;
257
258           # You might want to introspect the specification for the current route
259           my $spec = $c->openapi->spec;
260           unless ($spec->{'x-opening-hour'} == (localtime)[2]) {
261             return $c->render(openapi => [], status => 498);
262           }
263
264           my $age  = $c->param("age");
265           my $body = $c->req->json;
266
267           # $output will be validated by the OpenAPI spec before rendered
268           my $output = {pets => [{name => "kit-e-cat"}]};
269           $c->render(openapi => $output);
270         }
271
272         1;
273
274       The input will be validated using "openapi.valid_input" in
275       Mojolicious::Plugin::OpenAPI while the output is validated through then
276       openapi handler.
277
278   Route names
279       Routes will get its name from either "x-mojo-name" or from
280       "operationId" if defined in the specification.
281
282       The route name can also be used the other way around, to find already
283       defined routes. This is especially useful for Mojolicious::Lite apps.
284
285       Note that if spec_route_name is used then all the route names will have
286       that value as prefix:
287
288         spec_route_name            = "my_cool_api"
289         operationId or x-mojo-name = "Foo"
290         Route name                 = "my_cool_api.Foo"
291
292       You can also set "x-mojo-name" in the spec, instead of passing
293       spec_route_name to plugin():
294
295         {
296           "openapi": "3.0.2",
297           "info": { "version": "1.0", "title": "Some awesome API" },
298           "x-mojo-name": "my_cool_api"
299         }
300
301   Default response schema
302       A default response definition will be added to the API spec, unless
303       it's already defined. This schema will at least be used for invalid
304       input (400 - Bad Request) and invalid output (500 - Internal Server
305       Error), but can also be used in other cases.
306
307       See "default_response_codes" in Mojolicious::Plugin::OpenAPI and
308       "default_response_name" in Mojolicious::Plugin::OpenAPI for more
309       details on how to configure these settings.
310
311       The response schema will be added to your spec like this, unless
312       already defined:
313
314         {
315           ...
316           "components": {
317             ...
318             "schemas": {
319               ...
320               "DefaultResponse": {
321                 "type":     "object",
322                 "required": ["errors"],
323                 "properties": {
324                   "errors": {
325                     "type":  "array",
326                     "items": {
327                       "type":       "object",
328                       "required":   ["message"],
329                       "properties": {"message": {"type": "string"}, "path": {"type": "string"}}
330                     }
331                   }
332                 }
333               }
334             }
335           }
336         }
337
338       The "errors" key will contain one element for all the invalid data, and
339       not just the first one. The useful part for a client is mostly the
340       "path", while the "message" is just to add some human readable debug
341       information for why this request/response failed.
342
343   Rendering binary data
344       Rendering assets and binary data should be accomplished by using the
345       standard Mojolicious tools:
346
347         sub get_image {
348           my $c = shift->openapi->valid_input or return;
349           my $asset = Mojo::Asset::File->new(path => "image.jpeg");
350
351           $c->res->headers->content_type("image/jpeg");
352           $c->reply->asset($asset);
353         }
354

OpenAPIv2 to OpenAPIv3 conversion

356       Both online and offline tools are available. One example is of this is
357       <https://github.com/mermade/openapi-webconverter>
358

Known issues

360   File references
361       Relative file references like the following
362
363         "$ref": "my-cool-component.json#"
364         "$ref": "my-cool-component.json"
365
366       Will also be placed under '#/definitions/...', again producing a spec
367       output which will not pass validation.
368

SEE ALSO

370       Mojolicious::Plugin::OpenAPI, <https://openapis.org/specification>.
371
372
373
374perl v5.36.0                Mojoli2c0i2o3u-s0:1:-P2l0ugin::OpenAPI::Guides::OpenAPIv3(3)
Impressum