Coder Social home page Coder Social logo

mojolicious-plugin-openapi's Introduction

NAME

Mojolicious::Plugin::OpenAPI - OpenAPI / Swagger plugin for Mojolicious

SYNOPSIS

# It is recommended to use Mojolicious::Plugin::OpenAPI with a "full app".
# See the links after this example for more information.
use Mojolicious::Lite;

# Because the route name "echo" matches the "x-mojo-name", this route
# will be moved under "basePath", resulting in "POST /api/echo"
post "/echo" => sub {

  # Validate input request or return an error document
  my $c = shift->openapi->valid_input or return;

  # Generate some data
  my $data = {body => $c->req->json};

  # Validate the output response and render it to the user agent
  # using a custom "openapi" handler.
  $c->render(openapi => $data);
}, "echo";

# Load specification and start web server
plugin OpenAPI => {url => "data:///swagger.yaml"};
app->start;

__DATA__
@@ swagger.yaml
swagger: "2.0"
info: { version: "0.8", title: "Echo Service" }
schemes: ["https"]
basePath: "/api"
paths:
  /echo:
   post:
     x-mojo-name: "echo"
     parameters:
     - { in: "body", name: "body", schema: { type: "object" } }
     responses:
       200:
         description: "Echo response"
         schema: { type: "object" }

See Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv2 or Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv3 for more in depth information about how to use Mojolicious::Plugin::OpenAPI with a "full app". Even with a "lite app" it can be very useful to read those guides.

Looking at the documentation for "x-mojo-to" in Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv2 can be especially useful. (The logic is the same for OpenAPIv2 and OpenAPIv3)

DESCRIPTION

Mojolicious::Plugin::OpenAPI is Mojolicious::Plugin that add routes and input/output validation to your Mojolicious application based on a OpenAPI (Swagger) specification. This plugin supports both version 2.0 and 3.x, though 3.x might have some missing features.

Have a look at the "SEE ALSO" for references to plugins and other useful documentation.

Please report in issues or open pull requests to enhance the 3.0 support.

HELPERS

openapi.spec

$hash = $c->openapi->spec($json_pointer)
$hash = $c->openapi->spec("/info/title")
$hash = $c->openapi->spec;

Returns the OpenAPI specification. A JSON Pointer can be used to extract a given section of the specification. The default value of $json_pointer will be relative to the current operation. Example:

{
  "paths": {
    "/pets": {
      "get": {
        // This datastructure is returned by default
      }
    }
  }
}

openapi.validate

@errors = $c->openapi->validate;

Used to validate a request. @errors holds a list of JSON::Validator::Error objects or empty list on valid input.

Note that this helper is only for customization. You probably want "openapi.valid_input" in most cases.

openapi.valid_input

$c = $c->openapi->valid_input;

Returns the Mojolicious::Controller object if the input is valid or automatically render an error document if not and return false. See "SYNOPSIS" for example usage.

HOOKS

Mojolicious::Plugin::OpenAPI will emit the following hooks on the application object.

openapi_routes_added

Emitted after all routes have been added by this plugin.

$app->hook(openapi_routes_added => sub {
  my ($openapi, $routes) = @_;

  for my $route (@$routes) {
    ...
  }
});

This hook is EXPERIMENTAL and subject for change.

RENDERER

This plugin register a new handler called openapi. The special thing about this handler is that it will validate the data before sending it back to the user agent. Examples:

$c->render(json => {foo => 123});    # without validation
$c->render(openapi => {foo => 123}); # with validation

This handler will also use "renderer" to format the output data. The code below shows the default "renderer" which generates JSON data:

$app->plugin(
  OpenAPI => {
    renderer => sub {
      my ($c, $data) = @_;
      return Mojo::JSON::encode_json($data);
    }
  }
);

ATTRIBUTES

route

$route = $openapi->route;

The parent Mojolicious::Routes::Route object for all the OpenAPI endpoints.

validator

$jv = $openapi->validator;

Holds either a JSON::Validator::Schema::OpenAPIv2 or a JSON::Validator::Schema::OpenAPIv3 object.

METHODS

register

$openapi = $openapi->register($app, \%config);
$openapi = $app->plugin(OpenAPI => \%config);

Loads the OpenAPI specification, validates it and add routes to $app. It will also set up "HELPERS" and adds a before_render hook for auto-rendering of error documents. The return value is the object instance, which allow you to access the "ATTRIBUTES" after you load the plugin.

%config can have:

coerce

See "coerce" in JSON::Validator for possible values that coerce can take.

Default: booleans,numbers,strings

The default value will include "defaults" in the future, once that is stable enough.

default_response

Instructions for "add_default_response_schema" in JSON::Validator::Schema::OpenAPIv2. (Also used for OpenAPIv3)

format

Set this to a default list of file extensions that your API accepts. This value can be overwritten by "x-mojo-to" in Mojolicious::Plugin::OpenAPI::Guides::OpenAPIv2.

This config parameter is EXPERIMENTAL and subject for change.

log_level

log_level is used when logging invalid request/response error messages.

Default: "warn".

op_spec_to_route

op_spec_to_route can be provided if you want to add route definitions without using "x-mojo-to". Example:

$app->plugin(OpenAPI => {op_spec_to_route => sub {
  my ($plugin, $op_spec, $route) = @_;

  # Here are two ways to customize where to dispatch the request
  $route->to(cb => sub { shift->render(openapi => ...) });
  $route->to(ucfirst "$op_spec->{operationId}#handle_request");
}});

This feature is EXPERIMENTAL and might be altered and/or removed.

plugins

A list of OpenAPI classes to extend the functionality. Default is: Mojolicious::Plugin::OpenAPI::Cors, Mojolicious::Plugin::OpenAPI::SpecRenderer and Mojolicious::Plugin::OpenAPI::Security.

$app->plugin(OpenAPI => {plugins => [qw(+Cors +SpecRenderer +Security)]});

You can load your own plugins by doing:

$app->plugin(OpenAPI => {plugins => [qw(+SpecRenderer My::Cool::OpenAPI::Plugin)]});

renderer

See "RENDERER".

route

route can be specified in case you want to have a protected API. Example:

$app->plugin(OpenAPI => {
  route => $app->routes->under("/api")->to("user#auth"),
  url   => $app->home->rel_file("cool.api"),
});

skip_validating_specification

Used to prevent calling "errors" in JSON::Validator::Schema::OpenAPIv2 for the specification.

spec_route_name

Name of the route that handles the "basePath" part of the specification and serves the specification. Defaults to "x-mojo-name" in the specification at the top level.

spec, url

See "schema" in JSON::Validator for the different url formats that is accepted.

spec is an alias for "url", which might make more sense if your specification is written in perl, instead of JSON or YAML.

Here are some common uses:

$app->plugin(OpenAPI => {url  => $app->home->rel_file('openapi.yaml'));
$app->plugin(OpenAPI => {url  => 'https://example.com/swagger.json'});
$app->plugin(OpenAPI => {spec => JSON::Validator::Schema::OpenAPIv3->new(...)});
$app->plugin(OpenAPI => {spec => {swagger => "2.0", paths => {...}, ...}});

version_from_class

Can be used to overridden /info/version in the API specification, from the return value from the VERSION() method in version_from_class.

Defaults to the current $app. This can be disabled by setting the "version_from_class" to zero (0).

AUTHORS

Project Founder

Jan Henning Thorsen - [email protected]

Contributors

COPYRIGHT AND LICENSE

Copyright (C) Jan Henning Thorsen

This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.

SEE ALSO

mojolicious-plugin-openapi's People

Contributors

augensalat avatar cosmicnet avatar elcamlost avatar hem42 avatar jberger avatar jhthorsen avatar kberov avatar kiwiroy avatar knowledgejunkie avatar leejo avatar manuelm avatar manwar avatar mohawk2 avatar mrenvoize avatar openstrike avatar potatogim avatar preaction avatar reneeb avatar sebmourlhou avatar skeeve avatar soren avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mojolicious-plugin-openapi's Issues

Document `reply.openapi` in main module

Hi! First of all thanks for this great module, I discovered Swagger just when I was starting designing a simple API and... presto!, there Is a module for Mojolicious in CPAN.

The tutorial talks about reply.openapi a couple of times (e.g. here and here), pointing to non-existing documentation in the main module.

I was also curious why reply.openapi instead of openapi.reply, like the input validation stuff.

Spec's with boolean as types die. Conflict with CPAN boolean dists boolean::TO_JSON ?

Info: The boolean CPAN module is required for MongoDB.

I am new to Mojo JSON handling, but it seems there is a conflict once the CPAN 'boolean' module is installed. I could track the issue quite far, but don't understand how to patch this.

The CPAN boolean distribution has:

sub TO_JSON {
  Carp::croak "Need ref for this" unless ref $_[0];         # Added by myself for debugging
  ${$_[0]} ? \1 : \0

}

and expects this method not to be called with arguments, or as a constructor (which OpenAPI.pm obviously does). This causes wrong initialization with the construct JSON/Validator.pm '0.86' line 301:

  $data = $data->TO_JSON if UNIVERSAL::can($data, 'TO_JSON');

as ends into

'boolean'->TO_JSON
{
return ${ 'boolean' };
}

which die's because the string 'boolean' is not a ref.

QUESTION: Could someone fix this ?

INFO: My swagger2 json has under definitions 'boolean' as a type for 'complete'.

   "Order": {
        "type": "object",
        "properties": {
            "id": {
                "type": "integer",
                "format": "int64"
            },
            "Id": {
                "type": "integer",
                "format": "int64"
            },
            "quantity": {
                "type": "integer",
                "format": "int32"
            },
            "shipDate": {
                "type": "string",
                "format": "date-time"
            },
            "status": {
                "type": "string",
                "description": "Order Status"
            },
            "complete": {
                "type": "boolean"
            }
        }

Once I try to load it, it die's with this stack trace:

ERROR* parse_line: Need ref for this at /usr/local/share/perl/5.18.2/boolean.pm line 83.
boolean::TO_JSON("boolean") called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 301
JSON::Validator::_validate(JSON::Validator=HASH(0xea5d588), "boolean", "/definitions/Order/properties/complete/type", HASH(0xea2ead0)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 599
JSON::Validator::_validate_type_object(JSON::Validator=HASH(0xea5d588), HASH(0xeb59670), "/definitions/Order/properties/complete", HASH(0xea2e218)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 310
JSON::Validator::_validate(JSON::Validator=HASH(0xea5d588), HASH(0xeb59670), "/definitions/Order/properties/complete", HASH(0xea2e218)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 599
JSON::Validator::_validate_type_object(JSON::Validator=HASH(0xea5d588), HASH(0xeb93a18), "/definitions/Order/properties", HASH(0xea2e6f8)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 310
JSON::Validator::_validate(JSON::Validator=HASH(0xea5d588), HASH(0xeb93a18), "/definitions/Order/properties", HASH(0xea2e6f8)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 599
JSON::Validator::_validate_type_object(JSON::Validator=HASH(0xea5d588), HASH(0xec6eda0), "/definitions/Order", HASH(0xea364e0)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 310
JSON::Validator::_validate(JSON::Validator=HASH(0xea5d588), HASH(0xec6eda0), "/definitions/Order", HASH(0xea364e0)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 599
JSON::Validator::_validate_type_object(JSON::Validator=HASH(0xea5d588), HASH(0xec6eb30), "/definitions", HASH(0xea36468)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 310
JSON::Validator::_validate(JSON::Validator=HASH(0xea5d588), HASH(0xec6eb30), "/definitions", HASH(0xea36468)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 599
JSON::Validator::_validate_type_object(JSON::Validator=HASH(0xea5d588), HASH(0xe99cd00), "", HASH(0xea5d7c8)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 310
JSON::Validator::_validate(JSON::Validator=HASH(0xea5d588), HASH(0xe99cd00), "", HASH(0xea5d7c8)) called at /usr/local/share/perl/5.18.2/JSON/Validator.pm line 89
JSON::Validator::validate(JSON::Validator=HASH(0xea5d588), HASH(0xe99cd00)) called at /usr/local/share/perl/5.18.2/Mojolicious/Plugin/OpenAPI.pm line 130
Mojolicious::Plugin::OpenAPI::_load_spec(Mojolicious::Plugin::OpenAPI=HASH(0xea5d528), CellApp=HASH(0xeafb288), HASH(0xea74260)) called at /usr/local/share/perl/5.18.2/Mojolicious/Plugin/OpenAPI.pm line 21
Mojolicious::Plugin::OpenAPI::register(Mojolicious::Plugin::OpenAPI=HASH(0xea5d528), CellApp=HASH(0xeafb288), HASH(0xea74260)) called at /usr/local/share/perl/5.18.2/Mojolicious/Plugins.pm line 46
Mojolicious::Plugins::register_plugin(Mojolicious::Plugins=HASH(0xeb09f48), "OpenAPI", CellApp=HASH(0xeafb288), HASH(0xea74260)) called at /usr/local/share/perl/5.18.2/Mojolicious.pm line 175
Mojolicious::plugin(CellApp=HASH(0xeafb288), "OpenAPI", HASH(0xea74260)) called at mojo/cell_app/lib/CellApp.pm line 96

Nested $ref not works in body parameters (issue?)

Hi Jan,

I found the issue with nested $ref in body parameters...
I can't check the "customer" schema that is the part of the "order" schema...

Here is the example api.json:

{
  "swagger" : "2.0",
  "info" : { "version": "0.1", "title" : "Orders" },
  "schemes" : [ "http" ],
  "basePath" : "/",
  "paths" : {
    "/order" : {
      "post" : {
        "x-mojo-to" : "testcontroller#order",
        "parameters" : [
            { "in": "body", "name": "body", "schema": { "$ref": "#/definitions/customer" } }
        ],
        "responses" : {
          "200": {
            "description": "New order response",
            "schema": { "type": "object" }
          }
        }
      }
    }
  },
  "definitions": {
    "order": {
      "type": "object",
      "description": "New order data",
      "required": [ "customer" ],
      "properties": {
        "customer": { "$ref": "#/definitions/customer" }
      }
    },
    "customer": {
      "type": "object",
      "description": "Customer personal data",
      "required": [ "first_name", "last_name", "email" ],
      "properties": {
        "first_name": { "type": "string" },
        "last_name": { "type": "string" },
        "email": { "type": "string" },
        "phone": { "type": "string" }
      }
    }
  }
}

Test service:

#!/usr/bin/env perl

package TestAPI::Controller::Testcontroller;
use Mojo::Base 'Mojolicious::Controller';

sub order
{
    my $c = shift;

    $c->app->log->warn('Body: ' . $c->req->body);

    return unless ($c->openapi->valid_input);

    $c->render(openapi => { status => 'ok' });
}

#
package TestAPI;
use Mojo::Base 'Mojolicious';

sub startup
{
    shift->plugin( OpenAPI => { url => 'api.json' });
}

#
package main;
use strict;
use warnings;

require Mojolicious::Commands;
Mojolicious::Commands->start_app('TestAPI');

Example query:

curl -X POST -d '{"customer":{"first_name":"a","last_name":"b","email":"[email protected]"}}' http://127.0.0.1:3000/order

Response:

[Thu Feb  8 11:39:51 2018] [debug] POST "/order"
[Thu Feb  8 11:39:51 2018] [debug] Routing to controller "TestAPI::Controller::Testcontroller" and action "order"
[Thu Feb  8 11:39:51 2018] [warn] Body: {"customer":{"first_name":"a","last_name":"b","email":"[email protected]"}}
[Thu Feb  8 11:39:51 2018] [debug] Your secret passphrase needs to be changed
[Thu Feb  8 11:39:52 2018] [warn] OpenAPI <<< POST /order [{"message":"Missing property.","path":"\/body\/email"},{"message":"Missing property.","path":"\/body\/first_name"},{"message":"Missing property.","path":"\/body\/last_name"}]
[Thu Feb  8 11:39:52 2018] [debug] 400 Bad Request (0.00217000000000001s, 460.829/s)

So the question is: is it possible to use nested $ref by OpenAPI or it is the module issue?

endpoint.html.ep does not exist in __DATA__

[Mon Jul 24 05:39:56 2017] [debug] Template "mojolicious/plugin/openapi/endpoint.html.ep" not found

M::P::OpenAPI, line 839
%= include "mojolicious/plugin/openapi/endpoint"

but there is no
@@ mojolicious/plugin/openapi/endpoint.html.ep

security definitions

It looks like the plugin completely ignores security definitions. It would be really nice to be able to have an authentication method route to an auth controller and method.

For example,

securityDefinitions:
  AccessToken:
    x-mojo-to: 'user#token_auth'
    description: |
      For accessing the API a valid JWT token must be passed in the 'Authorization' header. A valid JWT token is generated by the /auth endpoint.

      The following syntax must be used in the 'Authorization' header:
        Bearer: xxxxxx.yyyyyyy.zzzzzz
    type: apiKey
    name: Authorization
    in: header

I know you can specify a single custom route to do authentication but the problem is that this is a catch all and doesn't support multiple authentication methods.

The problem I was running into is if I have a /api/login route that generates a JWT token obviously I don't want it to authenticate a JWT token that doesn't exist yet!

defaults broken in 1.22?

I just upgraded to 1.22 and immediately defaults for enums are not being passed as params any more. I have this in the spec:

  PCVersion:
    name: pcversion
    type: string
    in: query
    description: version of commands which will run on backend
    default: 10.1.0
    enum:
      - 9.6.1
      - 10.1.0

before, params always had "10.1.0" as the value of "pcversion" if nothing was passed but now it's just empty ...

Deprecation of Mojo::Util::slurp

With latest Mojolicious:

Mojo::Util::slurp is DEPRECATED in favor of Mojo::File::slurp at /usr/local/informatica/perl/lib/site_perl/5.24.0/Mojolicious/Plugin/OpenAPI.pm line 133.

Not every route is prefixed

	$app->plugin(OpenAPI => {
		spec_route_name => 'api',
	});

Not every route is prefixed

delete1

Because of this it create routes with conflicting names

Rendered spec is not valid under certain conditions

With the last version of this plugin / JSON::Validator.

For exemple, this spec (https://github.com/le-garff-yoann/mojolicious-plugin-openapi-issue-62/blob/master/share/t-app.json) is rendered on the basePath as:

{
  "basePath": "/api",
  "consumes": [
    "application/json"
  ],
  "definitions": {
    "__tmp_t-app_share_t-app_json-_responses_error": {
      "description": "Self sufficient",
      "schema": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      }
    }
  },
  "host": "localhost:3000",
  "info": {
    "license": {
      "name": "Apache License, Version 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "title": "t-app",
    "version": "0.1.0"
  },
  "paths": {
    "/t": {
      "get": {
        "operationId": "listT",
        "responses": {
          "200": {
            "description": "Self sufficient",
            "schema": {
              "items": {
                "type": "string"
              },
              "type": "array"
            }
          },
          "default": {
            "$ref": "#/definitions/__tmp_t-app_share_t-app_json-_responses_error"
          }
        },
        "tags": [
          "t"
        ],
        "x-mojo-to": "Controller::OpenAPI::T#list"
      }
    }
  },
  "produces": [
    "application/json"
  ],
  "responses": {
    "error": {
      "description": "Self sufficient",
      "schema": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      }
    }
  },
  "swagger": "2.0"
}

This rendered spec isn't valid if you try to load it with OpenAPI::Client - http://editor.swagger.io -http://bigstickcarpet.com/swagger-parser/www/index.html (while the original one is).

N.B:

I cannot tell if:

  • It's a bug (or a couple of bugs) recently introduced in this plugin or in JSON::Validator.
  • I'm missing a newly introduced feature (i mean a particular option of this plugin).

Default boolean values for yaml are turned into empty strings

definitions:
  data:
    type: object
    properties:
      bool_value:
        type: boolean
        default: false

is turned into:

"definitions" : {
  "data" : {
    "type" :"object",
    "properties" : {
      "bool_value" : {
        "default" : "",
        "type" : "boolean"
      }
    }
  }
}

Not sure if this is a limitation of yml or a bug with coercion.

"patternProperties" appears in a response definition after querying the relevant endpoint

I use the latest version of this plugin, JSON::[email protected], [email protected] and hypnotoad.

  1. Extract from my spec before the request on the /api/c endpoint:
        "/c": {
            "get": {
                "operationId": "listC",
                "parameters": [
                    {
                        "collectionFormat": "multi",
                        "default": [
                        ],
                        "in": "query",
                        "items": {
                            "type": "string"
                        },
                        "name": "tag",
                        "type": "array"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Self sufficient",
                        "schema": {
                            "items": {
                                "additionalProperties": false,
                                "properties": {
                                    "description": {
                                        "type": "string"
                                    },
                                    "name": {
                                        "type": "string"
                                    },
                                    "score": {
                                        "format": "int64",
                                        "minimum": 0,
                                        "type": "integer"
                                    }
                                },
                                "required": [
                                    "name",
                                    "description"
                                ],
                                "type": "object"
                            },
                            "type": "array"
                        }
                    },
                    "default": {
                        "description": "Self sufficient",
                        "schema": {
                            "additionalProperties": false,
                            "properties": {
                                "error": {
                                    "type": "string"
                                }
                            },
                            "required": [
                                "error"
                            ],
                            "type": "object"
                        }
                    }
                },
                "tags": [
                    "clover"
                ],
                "x-all-parameters": [
                    {
                        "collectionFormat": "multi",
                        "default": [
                        ],
                        "in": "query",
                        "items": {
                            "type": "string"
                        },
                        "name": "tag",
                        "type": "array"
                    }
                ],
                "x-mojo-to": "Controller::OpenAPI::C#list"
  1. I send a GET on /api/c.
  2. Get spec: it returns the same as 1. but with patterProperties (= {}) on /\/c/get/responses/200/schema/items.

This is annoying because OpenAPI / Swagger2 clients do not support this property.

N.B: Ofc, the situation is normal again when I restart my application.

Curious if you can reproduce something like this. Possibly related to my setup after all ....

Serving of the OpenAPI spec ought not to be transformed version

Further to discussion on #swagger. When I have a Mojolicious app that has a Mojolicious::Plugin::OpenAPI endpoint starting at /api that has a $ref, and I request /api, the $ref is:

Got: #/definitions/_api_data_yml-definitions/Whatever

Expected: #/definitions/Whatever

The reason to care about this is that my code reads the actual $ref to determine the return "type" of the request. This works great when using JSON::Validator::OpenAPI to read a spec directly off a disk, but not when read from an endpoint as mentioned above.

I understand that there is a concern about "leaking" x-mojo-* information in the spec, and would not be affected if just that were filtered out by default. I also understand there is a use-case for the bundling being still available, and I would also not be affected if that were available with e.g. a ?bundle=1 CGI arg on the spec. However, currently the specs being served I cannot use.

Tests fail (with old JSON::Validator 0.84)

The t/collectionformat.t test started to fail:

Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.
Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.
Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.

#   Failed test 'exact match for JSON Pointer "/errors/0/path"'
#   at t/collectionformat.t line 18.
#          got: '/ml'
#     expected: '/ri'
Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.
Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.

#   Failed test 'exact match for JSON Pointer "/errors/0/path"'
#   at t/collectionformat.t line 21.
#          got: '/ml'
#     expected: '/ri/0'
Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.
Use of uninitialized value $_ in addition (+) at /usr/perl5.16.3t/lib/site_perl/5.16.3/JSON/Validator/OpenAPI.pm line 256.
# Looks like you failed 2 tests of 13.
t/collectionformat.t ......... 
Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/13 subtests 

Statistical analysis thinks it's JSON::Validator 0.85 causing the problem:

****************************************************************
Regression 'mod:JSON::Validator'
****************************************************************
Name                   Theta          StdErr     T-stat
[0='const']           0.0000          0.0000       0.00
[1='eq_0.84']         0.0000          0.0000       0.00
[2='eq_0.85']         1.0000          0.0000    9097197740369964.00

R^2= 1.000, N= 29, K= 3
****************************************************************

Body parameters in HTML output

Consider the spec below. Since there can only be one body parameter definition, multiple body parameters have to be specifiec with a reference. However, when rendered with the automatic documentation URL (which is great, by the way), it does not resolve the reference and user is told in teh doc for the operation that there is a parameter called "AuthGenerate" which is not required. The actual params are spelled out correctly in the "Body" section for the operation but it is quite confusing for users to see a paramater called "AuthGenerate" which is not something they should really even see as it's just a name used internally to the spec to group body params. Perhaps these reference can be parsed out for the "Parameters" section so that the actual params and ther required status are visible, just like normal query params etc.?

swagger: '2.0'
info:
  title: REST API
  version: "1.0.0"
schemes:
  - https
basePath: /pcapiv1
produces:
  - application/json
paths:
  /auth:
    post:
      x-mojo-to: "auth#generate"
      summary: Generate JWT for username/password combination
      parameters:
        - name: AuthGenerate
          in: body
          description: username/password to be encoded as a JWT
          schema:
            $ref: '#/definitions/AuthGenerate'
      responses:
        default:
          description: Generic response object
          schema:
            $ref: '#/definitions/Response'
definitions:
  AuthGenerate:
    required:
      - username
      - password
      - domain
      - repository
    properties:
      username:
        description: username
        type: string
      password:
        description: password
        type: string
      domain:
        description: domain
        type: string
      repository:
        description: repository
        type: string
      securitydomain:
        description: Security Domain
        type: string
  Response:
    type: object
    description: JSON object with 'status' parameter and error array
    required:
      - status
      - errors
    properties:
      status:
        description: True/False status
        type: boolean
      errors:
        description: Array of any errors
        type: array
        items:
          type: string
      output:
        description: Array of any output
        type: array
        items:
          type: string

Can not disable coerce for all

Odd number of elements in anonymous hash at /home/kes/work/projects/tucha/monkeyman/app/tucha/../..//local/lib/perl5/JSON/Validator.pm line 119

$app->plugin(OpenAPI => {
	coerce => 0,
});

t/yaml.t: YAML::Syck test may be removed

JSON::Validator 2.00 does not support YAML::Syck anymore, and JSON::Validator::_load_yaml does not exist anymore, so the test case for YAML::Syck in t/yaml.t should probably be removed.

t/yaml.t may fail

On some of my smoker machines t/yaml.t fails:

# YAML::XS 0.66

#   Failed test 'Could not load Swagger2 plugin using YAML::XS'
#   at t/yaml.t line 20.
# Can't call method "can" on an undefined value at /home/cpansand/.cpan/build/2018011915/JSON-Validator-2.00-0/blib/lib/JSON/Validator.pm line 256.
# YAML::Syck 1.30

#   Failed test 'Could not load Swagger2 plugin using YAML::Syck'
#   at t/yaml.t line 20.
# Can't call method "can" on an undefined value at /home/cpansand/.cpan/build/2018011915/JSON-Validator-2.00-0/blib/lib/JSON/Validator.pm line 256.
# Looks like you failed 2 tests of 2.
t/yaml.t .............................. 
Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/2 subtests 

Statistical analysis suggests that the failures happen if YAML::XS < 0.67 is installed:

$ local-ctgetreports.pl --q 'qr:# YAML::XS (\S+)' Mojolicious-Plugin-OpenAPI-1.24
...
****************************************************************
Regression 'qr:# YAML::XS (\S+)'
****************************************************************
Name                   Theta          StdErr     T-stat
[0='const']          -0.0000          0.0000     -23.80
[1='eq_0.59']         0.0000          0.0000       7.55
[2='eq_0.62']         0.0000          0.0000       1.64
[3='eq_0.63']        -0.0000          0.0000      -1.83
[4='eq_0.65']        -0.0000          0.0000      -4.78
[5='eq_0.66']         0.0000          0.0000       8.43
[6='eq_0.67']         1.0000          0.0000    17220411790955142.00
[7='eq_0.68']         1.0000          0.0000    21047169966722948.00
[8='eq_0.69']         1.0000          0.0000    29022272672653860.00

R^2= 1.000, N= 124, K= 9
****************************************************************

204 No Content response hangs for 15 seconds

For example if I call,

$c->render(openapi => {}, status => 204);

It takes 15 seconds to return 204 No Content.

If I call,

$c->render( status => 204 );

I get this back without any lag time,

{ "errors": [ { "message": "Not implemented.", "path": "/" } ], "status": 501 }

Minimum version for JSON::Validator?

It seems that JSON::Validator 0.95 is required. With older version my smokers report failures:

Can't locate object method "load_and_validate_schema" via package "JSON::Validator::OpenAPI::Mojolicious" at /home/cpansand/.cpan/build/2017030221/Mojolicious-Plugin-OpenAPI-1.12-p_aD4E/blib/lib/Mojolicious/Plugin/OpenAPI.pm line 34.
t/autorender.t ............... 
Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run 
...

How to get full spec

After update I see dump spec in this view

​​\ {
    parameters    [
        [0] {
            $ref   "#/parameters/event_id"
        } (tied to JSON::Validator::Ref)
    ],
    responses     {
        200       {
            description   "Get event",
            schema        {
                $ref   "#/definitions/event_result"
            } (tied to JSON::Validator::Ref)
        },
        202       {
            description   "Error",
            schema        {
                $ref   "#/definitions/error"
            } (tied to JSON::Validator::Ref)
        },
        default   {
            description   "Default response.",
            schema        {
                properties   {
                    errors   {
                        items   {
                            properties   {
                                message   {
                                    type   "string"
                                },
                                path      {
                                    type   "string"
                                }
                            },
                            required     [
                                [0] "message"
                            ],
                            type         "object"
                        },
                        type    "array"
                    }
                },
                required     [
                    [0] "errors"
                ],
                type         "object"
            }
        }
    },
    x-mojo-name   "get_event",
    x-mojo-to     "Admin::Events#get_event"
}

How to get full spec with structs under ref?

Is it possible to validate all requests to api inside one under function?

I want to validate all requests against openapi inside under sub. (I use Mojo). Earlier, I achieved it like this:

sub under_openapi {
    ....
     my $spec = $self->match()->endpoint()->pattern()->defaults()->{'openapi.op_spec'};
     $self->stash('openapi.op_spec' => $spec);
     my @errors = $self->openapi()->validate();
    ...
}

After this release, I modified (and simplified) it to

sub under_openapi {
    ....
    my $spec =  $self->openapi()->spec();
    $self->stash('openapi.parameters' => $spec->{'parameters'});
    my @errors = $self->openapi()->validate();
    ...
}

So,

  1. why do you read parameters from stash inside _helper_validate, and not from $spec itself? Looks like correct data is already there.

  2. why not to make validation by default? It can be configured via constructor parameters.

`in: body` parameter can only be JSON and I'm not sure it's right

During call to $c->openapi->validate existense of in: body parameter is currently verified via $c->req->json, and json method returns something only if $c->req is a valid JSON.

Relevant code lines:
https://github.com/jhthorsen/json-validator/blob/master/lib/JSON/Validator/OpenAPI.pm#L58
https://github.com/jhthorsen/json-validator/blob/master/lib/JSON/Validator/OpenAPI/Mojolicious.pm#L11

But Swagger 2.0 spec doesn't seem to enforce for body parameters to be JSON. Body parameter must be defined using Schema Object, but

Unlike previous versions of Swagger, Schema definitions can be used to describe primitive and arrays as well.

http://swagger.io/specification/#fixed-fields-45
http://swagger.io/specification/#primitive-sample-86

deep recursion in Mojo::JSON from swagger api file with many $ref's

The following gist includes a small test case using Mojolicious::Plugin::OpenAPI. When visiting the base_path (/v1) the plugin attempts to serve the api spec, as documented. The html documentation renders fine, but the json version hangs on deep recursion. The swagger.io api editor tells me the included yaml swagger file contains no errors. It seems that Mojo::JSON's naive traversal of the resulting perl structure is at fault:

https://gist.github.com/stephenhoward/20e599e4bcc8c7cf6458ccba53e29bb0

Incorrect disambiguation of path by pattern

I have a spec that defines ambiguous paths like /user/list and /user/{id}. Based on some minimal tests I've run, this should not be a problem. And using plain Mojolicious, as long as the more specific path comes first, this definitely works. But I've bumped into at least one case in which this does not happen correctly.

I've tried to put together the smallest demo application demonstrating this problem, which is hosted in its own repository. It can be executed with morbo bin/server and tested with mojo get localhost:3000/decode, which should print {"target":"decode"} (but doesn't).

The problematic part of the API spec is this:

paths:
  /decode:
    get:
      operationId: "decode"
      x-mojo-to: "controller#decode"
      parameters: []
      responses:
        200:
          description: Success

  /{id}:
    get:
      operationId: "id"
      x-mojo-to: "controller#id"
      parameters:
        - name: id
          in: query
          required: true
          type: string
      responses:
        200:
          description: Success

I'm still trying to figure out where the problem is, but I'd really like to be able to have this plugin disambiguate these paths. Or am I doing something wrong?

recent update breaks readOnly properties

In my swagger spec I have some properties, that are required, set as readOnly. This means it would not require the parameter in the object if it was being sent as an argument and it would only require the readOnly property if the object was being sent in a response.

Since updating from 1.21 to 1.23 it seems to no longer respect the readOnly attribute!

bundling split specs

I would love to see a parallel to the 'bundle' command explained here: https://github.com/BigstickCarpet/swagger-parser/blob/master/docs/swagger-parser.md#bundleapi-options-callback (code at: https://github.com/BigstickCarpet/json-schema-ref-parser/blob/master/lib/bundle.js)

This would allow us to remove our dependency on Data::Dumper for a 'crude' but recursive loop resistant serialisation of the specification for outputting to HTML documentation (and should also serve to fix the .json rendering for the whole spec which currently goes into an endless loop (or rather just 500's when we hit max depth in your chosen JSON module) for recursive schema's.

I intend to look at this.. hopefully getting my head around the javascript implementation with the aim of porting similar into JSON::Validator.. this is more a marker of my intention.

Unexpected error message when response code is not allowed

Hi,

with version 1.25 of this plugin I notice an unexpected behaviour.

When my application is responding with a response code that is not specified in the API specification, I get the following error message:

[warn] OpenAPI >>> POST <ROUTE> [{"message":"Expected object - got null.","path":"\/"}]

I'd expect a specific error message telling me that the response code is not specified in the API specification (or something like that).

Headers validation

Mojolicious application (if it stays behind some frontend server like nginx) get headers in uppercase and converts standard headers to its original names in Mojo::Headers package.

So if i desclare header parameter like this:

parameters:
  some-header-param:
    name: CamelCase
    required: true
    type: string

and client sends this header, JSON::Validator::OpenApi will get header name as CAMELCASE (via mojo_ctrl->req->headers->to_hash) and validation will fail.

What is recommended way to deal with this situation?

Double resolve of specification

We're resolving the specification twice during register.

sub register {
  my ($self, $app, $config) = @_;
  my $api_spec = $self->_load_spec($app, $config);                             # <-- First resolve

  unless ($app->defaults->{'openapi.base_paths'}) {
    $app->helper('openapi.validate'    => \&_validate);
    $app->helper('openapi.valid_input' => sub { _validate($_[0]) ? undef : $_[0] });
    $app->helper('openapi.spec'        => \&_helper_spec);
    $app->helper('reply.openapi'       => \&_reply);
    $app->hook(before_render => \&_before_render);
    $app->renderer->add_handler(openapi => \&_render);
    push @{$app->renderer->classes}, __PACKAGE__;
  }

  $self->{log_level} = $ENV{MOJO_OPENAPI_LOG_LEVEL} || $config->{log_level} || 'warn';
  $self->{renderer} = $config->{renderer} || \&_render_json;
  $self->_validator->schema($api_spec->data)->coerce($config->{coerce} // 1);  # <-- Second Resolve
  $self->_add_routes($app, $api_spec, $config);
}

Initially, I thought this was just a bit inefficient, but it also seems to lead to a deeper problem inside JSON::Validator whereby the register call never completes. I've tracked it down to an infinite recursion of the while loop in _resolve_schema.

I'm struggling to write a test for either.. my initial attempts are in the currently failing recursion branch.

OpenAPI plugin error from "spec/event.yml#/paths/~1event~1update"

Hi,

We've been using the OpenAPI for quite a while and everything seems to be working really well in our environment.

However, just in the recently couple weeks, when starting server in development environment, I'm getting error complaining

Can't load application from file "/work/script/app.pl": Can't use string ("spec/event.yml#/paths/~1event~1u"...) as a HASH ref while "strict refs" in use at /home/build/.plenv/versions/5.24.0/lib/perl5/site_perl/5.24.0/Mojolicious/Plugin/OpenAPI.pm line 102.

My OpenAPI version is 1.21, mojo version is 7.39. Please refer to the bottom about the spec content.

While debugging the program, line 102 of OpenAPI.pm was giving the trouble:
my $name = $op_spec->{'x-mojo-name'} || $op_spec->{operationId};
$op_spec turns out to be a string and has the content of spec/event.yml#/paths/~1event~1update.

If I replace path ref with normal content, the program will run well. However, we've been using the same spec for quite a long time and it is only recently that it failed to load. I am not sure whether there are any change for the code base or the dependent modules.

It is highly appreciated if you could have any pointers or suggestions.

Regards,
Nancy

file spec.yml:

swagger: '2.0'

info:
  title: YBI Distribution API
  description: Service to handle all functions relating to distributing listings to 3rd parties
  version: "1.3.6"

schemes:
  - https
host: xxx
basePath: /xxx/v1
produces:
  - application/json
consumes:
  - application/json
paths:
      /event/update:
    $ref: spec/event.yml#/paths/~1event~1update

file spec/event.yml

paths:
  /event/update:
    post:
      summary: Trigger an update to 1 or more properties
      description: Notify the API of an update that needs processing.
      x-mojo-to:
        controller: Event
        action: Update
      parameters:
        - name: "events"
          in: "body"
          description: "Data structure of events to process"
          required: true
          schema:
            $ref: "#/definitions/events"
      responses:
        200:
          $ref: "#/responses/updateSuccess"
        default:
          $ref: '../spec.yml#/responses/http_status'

Tried to follow the tutorial and figure it out from the docs, but..

Mojolicious::Plugin::OpenAPI::Guides::Tutorial

I got my rest demo app running and copy pasted the spesification json (note: there is extra bracket on line 14 which give syntax error)

For the MyApp::Controller::Pet I had to add "use Mojo::Base 'Mojolicious::Controller'", because of error: Class "MyApp::Controller::Pet" is not a controller

After that I'm getting this error:
Log output:
[warn] OpenAPI >>> GET /api/pets [{"message":"Expected object - got array.","path":"\/"}]

Browser output:
{"errors":[{"message":"Expected object - got array.","path":"\/"}],"status":500}

And I don't have a clue why this isn't working. Any help on this? :)

I tried changing $c->render(openapi => $output) to $c->render(json => $output) to skip validation, but it doesn't had any effect. Got the same error.

Mojolicious is very new for me so this can be some basic stuff that I just don't know.

Ambigious error message

"Using default_handler to render data since 'openapi' was not found in stash. Set 'handler' in stash to avoid this message."

Do you mean set 'openapi' in stash?

[error] Unsupported $in: . Please report at https://github.com/jhthorsen/json-validator at

Hi, Jan!

I have some route in spec

  '/question/answer':
    post:
      x-mojo-name: save_answer
      x-mojo-to: 'Admin::Questions#save_answer'
      parameters:
        - $ref: '#/parameters/question_id_post'
        - $ref: '#/parameters/event_id_post'
        - name: answer
          in: formData
          type: string
          required: true
      responses:
        200:
          description: Add answer to question
          schema:
            $ref: '#/definitions/success'
        202:
          description: Add or update customer and add to calendar
          schema:
            $ref: '#/definitions/error'

and when I send data to this route a have that errot

[Sun Nov 19 08:14:26 2017] [debug] Routing to controller "Pi::Controller::Admin::Questions" and action "save_answer"
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI.pm line 49.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI.pm line 53.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI.pm line 58.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI/Mojolicious.pm line 7.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI/Mojolicious.pm line 10.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI/Mojolicious.pm line 13.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI/Mojolicious.pm line 16.
Use of uninitialized value $in in string eq at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI/Mojolicious.pm line 20.
Use of uninitialized value $_[0] in concatenation (.) or string at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI.pm line 294.
[Sun Nov 19 08:14:26 2017] [error] Unsupported $in: . Please report at https://github.com/jhthorsen/json-validator at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI.pm line 294.
JSON::Validator::OpenAPI::_confess_invalid_in(undef) called at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI/Mojolicious.pm line 24
JSON::Validator::OpenAPI::Mojolicious::_get_request_data(JSON::Validator::OpenAPI::Mojolicious=HASH(0x3bf7838), Pi::Controller::Admin::Questions=HASH(0x3eda788), undef) called at /usr/local/share/perl/5.22.1/JSON/Validator/OpenAPI.pm line 59
JSON::Validator::OpenAPI::validate_request(JSON::Validator::OpenAPI::Mojolicious=HASH(0x3bf7838), Pi::Controller::Admin::Questions=HASH(0x3eda788), HASH(0x3e56bd0), HASH(0x3eebb10)) called at /usr/local/share/perl/5.22.1/Mojolicious/Plugin/OpenAPI.pm line 380
Mojolicious::Plugin::OpenAPI::_validate(Pi::Controller::Admin::Questions=HASH(0x3eda788)) called at /usr/local/share/perl/5.22.1/Mojolicious/Plugin/OpenAPI.pm line 50
Mojolicious::Plugin::OpenAPI::ANON(Pi::Controller::Admin::Questions=HASH(0x3eda788)) called at /usr/local/share/perl/5.22.1/Mojolicious/Renderer.pm line 67
Mojolicious::Renderer::Helpers::3fc254888e095ff18bc36e1776ca6662::valid_input(Mojolicious::Renderer::Helpers::3fc254888e095ff18bc36e1776ca6662=REF(0x3f1abe0)) called at lib/Pi/Controller/Admin/Questions.pm line 59
Pi::Controller::Admin::Questions::save_answer(Pi::Controller::Admin::Questions=HASH(0x3eda788)) called at /usr/local/share/perl/5.22.1/Mojolicious.pm line 138
Mojolicious::ANON(undef, Pi::Controller::Admin::Questions=HASH(0x3eda788), CODE(0x3f14ec0), 1) called at /usr/local/share/perl/5.22.1/Mojolicious/Plugins.pm line 15
Mojolicious::Plugins::ANON() called at /usr/local/share/perl/5.22.1/Mojolicious/Plugins.pm line 18
Mojolicious::Plugins::emit_chain(Mojolicious::Plugins=HASH(0x30e2f78), "around_action", Pi::Controller::Admin::Questions=HASH(0x3eda788), CODE(0x3f14ec0), 1) called at /usr/local/share/perl/5.22.1/Mojolicious/Routes.pm line 87
Mojolicious::Routes::_action(Mojolicious::Lite=HASH(0x30b8458), Pi::Controller::Admin::Questions=HASH(0x3eda788), CODE(0x3f14ec0), 1) called at /usr/local/share/perl/5.22.1/Mojolicious/Routes.pm line 166
Mojolicious::Routes::_controller(Mojolicious::Routes=HASH(0x30e2b10), Mojolicious::Controller=HASH(0x3e8c428), HASH(0x3ed9ac8), 1) called at /usr/local/share/perl/5.22.1/Mojolicious/Routes.pm line 36
Mojolicious::Routes::continue(Mojolicious::Routes=HASH(0x30e2b10), Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious/Routes.pm line 38
Mojolicious::Routes::continue(Mojolicious::Routes=HASH(0x30e2b10), Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious/Routes.pm line 44
Mojolicious::Routes::dispatch(Mojolicious::Routes=HASH(0x30e2b10), Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious.pm line 129
Mojolicious::dispatch(Mojolicious::Lite=HASH(0x30b8458), Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious.pm line 139
Mojolicious::ANON(undef, Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious/Plugins.pm line 15
Mojolicious::Plugins::ANON() called at /usr/local/share/perl/5.22.1/Mojolicious.pm line 201
eval {...} called at /usr/local/share/perl/5.22.1/Mojolicious.pm line 201
Mojolicious::_exception(CODE(0x3e77768), Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious/Plugins.pm line 15
Mojolicious::Plugins::ANON() called at /usr/local/share/perl/5.22.1/Mojolicious/Plugins.pm line 18
Mojolicious::Plugins::emit_chain(Mojolicious::Plugins=HASH(0x30e2f78), "around_dispatch", Mojolicious::Controller=HASH(0x3e8c428)) called at /usr/local/share/perl/5.22.1/Mojolicious.pm line 145
Mojolicious::handler(Mojolicious::Lite=HASH(0x30b8458), Mojo::Transaction::HTTP=HASH(0x3041220)) called at /usr/local/share/perl/5.22.1/Mojo/Server.pm line 68
Mojo::Server::ANON(Mojo::Server::Daemon=HASH(0x14333d0), Mojo::Transaction::HTTP=HASH(0x3041220)) called at /usr/local/share/perl/5.22.1/Mojo/EventEmitter.pm line 15
Mojo::EventEmitter::emit(Mojo::Server::Daemon=HASH(0x14333d0), "request", Mojo::Transaction::HTTP=HASH(0x3041220)) called at /usr/local/share/perl/5.22.1/Mojo/Server/Daemon.pm line 103
Mojo::Server::Daemon::ANON(Mojo::Transaction::HTTP=HASH(0x3041220)) called at /usr/local/share/perl/5.22.1/Mojo/EventEmitter.pm line 15
Mojo::EventEmitter::emit(Mojo::Transaction::HTTP=HASH(0x3041220), "request") called at /usr/local/share/perl/5.22.1/Mojo/Transaction/HTTP.pm line 60
Mojo::Transaction::HTTP::server_read(Mojo::Transaction::HTTP=HASH(0x3041220), "POST /api/question/answer HTTP/1.1\x{d}\x{a}Connection: upgrade\x{d}\x{a}Host"...) called at /usr/local/share/perl/5.22.1/Mojo/Server/Daemon.pm line 219
Mojo::Server::Daemon::_read(Mojo::Server::Daemon=HASH(0x14333d0), "e8b245ab2107bbd3d8815a218523c2d4", "POST /api/question/answer HTTP/1.1\x{d}\x{a}Connection: upgrade\x{d}\x{a}Host"...) called at /usr/local/share/perl/5.22.1/Mojo/Server/Daemon.pm line 200
Mojo::Server::Daemon::ANON(Mojo::IOLoop::Stream=HASH(0x3dc59f0)) called at /usr/local/share/perl/5.22.1/Mojo/EventEmitter.pm line 15
Mojo::EventEmitter::emit(Mojo::IOLoop::Stream=HASH(0x3dc59f0), "read", "POST /api/question/answer HTTP/1.1\x{d}\x{a}Connection: upgrade\x{d}\x{a}Host"...) called at /usr/local/share/perl/5.22.1/Mojo/IOLoop/Stream.pm line 99
Mojo::IOLoop::Stream::_read(Mojo::IOLoop::Stream=HASH(0x3dc59f0)) called at /usr/local/share/perl/5.22.1/Mojo/IOLoop/Stream.pm line 48
Mojo::IOLoop::Stream::ANON(Mojo::Reactor::Poll=HASH(0x26cf498)) called at /usr/local/share/perl/5.22.1/Mojo/Reactor/Poll.pm line 143
eval {...} called at /usr/local/share/perl/5.22.1/Mojo/Reactor/Poll.pm line 143
Mojo::Reactor::Poll::_try(Mojo::Reactor::Poll=HASH(0x26cf498), "I/O watcher", CODE(0x2f9e998), 0) called at /usr/local/share/perl/5.22.1/Mojo/Reactor/Poll.pm line 58
Mojo::Reactor::Poll::one_tick(Mojo::Reactor::Poll=HASH(0x26cf498)) called at /usr/local/share/perl/5.22.1/Mojo/Reactor/Poll.pm line 99
Mojo::Reactor::Poll::start(Mojo::Reactor::Poll=HASH(0x26cf498)) called at /usr/local/share/perl/5.22.1/Mojo/IOLoop.pm line 136
Mojo::IOLoop::start(Mojo::IOLoop=HASH(0x2605140)) called at /usr/local/share/perl/5.22.1/Mojo/Server/Daemon.pm line 39
Mojo::Server::Daemon::run(Mojo::Server::Daemon=HASH(0x14333d0)) called at /usr/local/share/perl/5.22.1/Mojo/Server/Morbo.pm line 69
Mojo::Server::Morbo::_spawn(Mojo::Server::Morbo=HASH(0x1433298)) called at /usr/local/share/perl/5.22.1/Mojo/Server/Morbo.pm line 54
Mojo::Server::Morbo::_manage(Mojo::Server::Morbo=HASH(0x1433298)) called at /usr/local/share/perl/5.22.1/Mojo/Server/Morbo.pm line 34
Mojo::Server::Morbo::run(Mojo::Server::Morbo=HASH(0x1433298), "myapp.pl") called at /usr/local/bin/morbo line 19

[Sun Nov 19 08:14:26 2017] [debug] 500 Internal Server Error (0.008902s, 112.334/s)

This happened when I installed the latest version of the packages
cpanm Devel::Cycle ojo::Redis2 Mojolicious Minion Mojo::Pg DDP Mojo::mysql PadWalker Mojo::SQLite Mojolicious::Plugin::OpenAPI YAML::Syck List::MoreUtils Mojolicious::Plugin::ShareHelpers

Before the update, there were no such errors.

I need help

Array items in querystring

If I am using parameters in querystring - validation fails, if only one parameter specified.

curl '...?phone=1&phone=2' - success
curl '...?phone=1' - fail with error: Expected array - got string.","path":"/phone

Schema example

    get:
...
      parameters:
        -
          in: query
          name: phone
          type: array
          required: true
          minItems: 1
          items:
            type: string

Code in SYNOPSYS doesn't work

use Mojolicious::Lite;
 
# Will be moved under "basePath", resulting in "POST /api/echo"
post "/echo" => sub {
 
  # Validate input request or return an error document
  my $c = shift->openapi->valid_input or return;
 
  # Generate some data
  my $data = {body => $c->validation->param("body")};
 
  # Validate the output response and render it to the user agent
  # using a custom "openapi" handler.
  $c->render(openapi => $data);
}, "echo";
 
# Load specification and start web server
plugin OpenAPI => {url => "data://main/api.json"};
app->start;
 
__DATA__
@@ api.json
{
  "swagger" : "2.0",
  "info" : { "version": "0.8", "title" : "Pets" },
  "schemes" : [ "http" ],
  "basePath" : "/api",
  "paths" : {
    "/echo" : {
      "post" : {
        "x-mojo-name" : "echo",
        "parameters" : [
          { "in": "body", "name": "body", "schema": { "type" : "object" } }
        ],
        "responses" : {
          "200": {
            "description": "Echo response",
            "schema": { "type": "object" }
          }
        }
      }
    }
  }
}

If simply run this code with morbo you will get a JSON::Validator error:

api.json could not be found in __DATA__ section of main. at /usr/local/share/perl/5.22.1/JSON/Validator.pm line 212

Path-level parameters

The OpenAPI spec allows for path-level parameters as defined here: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#pathItemObject . These are especially useful for DRY on parameters which are in the path that are then shared by all the methods.

To be fair I haven't tried them out yet, but @jhthorsen mentioned on irc that he doubted that the plugin supports them, so this issue is at least a tracker for confirming that it does handle such parameter definitions and to implement them if necessary.

Can't validate yml schema against OpenApi

New Mojolicious::Plugin::OpenApi unlike the old Mojoliciuous::Plugin::Swagger2 do not perform type coercion for booleans on OpenApi validator object if we load yaml spec.

Mojoliciuous::Plugin::Swagger2 spec vaildation

package Swagger2;
....
sub validate {
  my $self = shift;
  $self->_validator->validate($self->expand->api_spec->data, $self->_specification->data);
}

here we use same validtor object to resolve application spec and swagger spec. And when we load Yaml validator object set boolean coercion and Swagger2->validate method works fine.

Mojoliciuous::Plugin::OpenApi spec vaildation

package Mojolicious::Plugin::OpenAPI;
...
sub _load_spec {
  my ($self, $app, $config) = @_;
  my $openapi = JSON::Validator->new->schema(JSON::Validator::OpenAPI::SPECIFICATION_URL());
  my ($api_spec, @errors);

  # first check if $ref is in the right place,
  # and then check if the spec is correct
  for my $r (sub { }, undef) {
    next if $r and $config->{allow_invalid_ref};
    my $jv = JSON::Validator->new;
    $jv->resolver($r) if $r;
    $api_spec = $jv->schema($config->{url})->schema;
    @errors   = $openapi->validate($api_spec->data);
    die join "\n", "[OpenAPI] Invalid spec:", @errors if @errors;
  }

  warn "[OpenAPI] Loaded $config->{url}\n" if DEBUG;
  return $api_spec;
}

here we use different validtor objects to resolve application spec and swagger spec. And when we load Yaml $openapi validator object do not set boolean coercion. Validation fails with counteruntuitive messages.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.