From affb451dc3e5f1c9544acdbe2f031dc2f40c98b6 Mon Sep 17 00:00:00 2001 From: reneeb Date: Wed, 30 Jan 2019 10:08:48 +0100 Subject: [PATCH 1/2] Fix HEAD requests With newer version of Mojolicious::Plugin::OpenAPI HEAD requests are broken as no spec can be found. Hence the default_spec is used - which requires the 'errors' property. But usually a HEAD request is successful, hence no 'errors' property. This leads to a '500 Internal Server Error' response. A HEAD request is some kind of a GET request (it requests the headers that would be returned if the resource was requested with a GET request. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD). So the HEAD request should be treated as a special case. --- lib/Mojolicious/Plugin/OpenAPI.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Mojolicious/Plugin/OpenAPI.pm b/lib/Mojolicious/Plugin/OpenAPI.pm index eac36f9..3043799 100644 --- a/lib/Mojolicious/Plugin/OpenAPI.pm +++ b/lib/Mojolicious/Plugin/OpenAPI.pm @@ -203,7 +203,8 @@ sub _helper_get_spec { $jp ||= [paths => $s->{'openapi.path'}]; } - push @$jp, lc $c->req->method if $jp and $path ne 'for_path'; # Internal for now + my $method = lc $c->req->method; + push @$jp, ( $method eq 'head' ? 'get' : $method ) if $jp and $path ne 'for_path'; # Internal for now return $jp ? $self->validator->get($jp) : undef; } From 69f3983448f703e2074dc23e3f5ccb158bf020fc Mon Sep 17 00:00:00 2001 From: reneeb Date: Wed, 30 Jan 2019 10:12:15 +0100 Subject: [PATCH 2/2] add test case for head request --- t/head_request.t | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 t/head_request.t diff --git a/t/head_request.t b/t/head_request.t new file mode 100644 index 0000000..c685daa --- /dev/null +++ b/t/head_request.t @@ -0,0 +1,89 @@ +use Mojo::Base -strict; +use Test::Mojo; +use Test::More; + +make_app(); +make_controller(); + +my $t = Test::Mojo->new('Myapp'); + +$t->head_ok('/api')->status_is(200); +$t->head_ok('/api/pets')->status_is(200); + +done_testing; + +sub make_app { + eval <<'HERE' or die $@; + package Myapp; + use Mojo::Base "Mojolicious"; + + sub startup { + my $app = shift; + $app->plugin("OpenAPI" => {url => "data://main/myapi.json"}); + } + + $ENV{"Myapp.pm"} = 1; +HERE +} + +sub make_controller { + eval <<'HERE' or die $@; + 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; + + # $c->openapi->valid_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->render(openapi => $output); + } + + $ENV{"Myapp/Controller/Pet.pm"} = 1; +HERE +} + +__DATA__ +@@ myapi.json +{ + "swagger": "2.0", + "info": { "version": "1.0", "title": "Some awesome API" }, + "basePath": "/api", + "paths": { + "/pets": { + "get": { + "operationId": "getPets", + "x-mojo-name": "get_pets", + "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": "object", + "properties": { + "pets": { + "type": "array", + "items": { "type": "object" } + } + } + } + } + } + } + } + } +}