---
name: "Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3"
section: "3pm"
platform: "linux"
package: "libmojolicious-plugin-openapi-perl"
version: "5.11-1"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3"
---

# Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3(3pm)

Mojolicious \<3 OpenAPI v3

## NAME

Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3 - Mojolicious \<3 OpenAPI v3

## OVERVIEW

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

## TUTORIAL

### Specification

This 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:

- •

  openapi, info and paths

  These three sections are required to make the specification valid. Check out \<https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md\> for a complete reference to the specification.

- •

  parameters, requestBody and responses

  `"parameters"`, `"requestBody"` and `"responses"` will be used to define input and output validation rules, which is used by "openapi.input" in Mojolicious::Plugin::OpenAPI and when rendering the response back to the client, using `"render(openapi => ...)"`.

  Here OpenAPIv3 input differs from the v2 spec, where `"parameters"` is used for input in the path or query of the request. The `"requestBody"` is used for input passed in the body.

  Have a look at "RENDERER" in Mojolicious::Plugin::OpenAPI for more details about output rendering.

- •

  operationId and x-mojo-name

  See "Route names".

- •

  x-mojo-placeholder

  `"x-mojo-placeholder"` can be used inside a parameter definition to instruct Mojolicious to parse a path part in a certain way. Example:

  ```
    "parameters": [
      {
        "x-mojo-placeholder": "#",
        "in": "path",
        "name": "email",
        "type": "string"
      }
    ]
  ```

  See Mojolicious::Guides::Routing for more information about "standard", "relaxed" and "wildcard" placeholders. The default is to use the "standard" ("/:foo") placeholder.

- •

  x-mojo-to

  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 flattened. 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}, ["format": ["json"]]]
    $route->to("pet#list", {foo => 123});
    $route->pattern->constraints->{format} = ["json"];
  ```

- •

  security and securitySchemes

  The securityScheme is added under components, where one way is to have the client place an apiKey in the header of the request

  ```
    {
      ...
      "components": {
        "securitySchemes": {
          "apiKey": {
            "name": "X-Api-Key",
            "in": "header",
            "type": "apiKey"
          }
        }
      }
    }
  ```

  It is then referenced under the path object as security like this

  ```
    {
      ...
      "paths": {
        "/pets": {
          "get": {
            "operationId": "getPets",
            ...
            "security": [
              {
                "apiKey": []
              }
            ]
          }
        }
      }
    }
  ```

  You can then utilize security, by adding a security callback when loading the plugin

  ```
    $self->plugin(
      OpenAPI => {
        spec     => $self->static->file("openapi.json")->path,
        security => {
          apiKey => sub {
            my ($c, $definition, $scopes, $cb) = @_;
            if (my $key = $c->tx->req->content->headers->header('X-Api-Key')) {
              if (got_valid_api_key()) {
                return $c->$cb();
              }
              else {
                return $c->$cb('Api Key not valid');
              }
            }
            else {
              return $c->$cb('Api Key header not present');
            }
          }
        }
      }
    );
  ```

*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 names

Routes 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 schema

A 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 data

Rendering 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 conversion

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

## Known issues

### File references

Relative 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 ALSO

Mojolicious::Plugin::OpenAPI, \<https://openapis.org/specification\>.
