jhthorsen / mojolicious-plugin-openapi

OpenAPI / Swagger plugin for Mojolicious
53 stars 41 forks source link

A requestBody with a fully-specified content type and a string type is always an error #227

Closed briandfoy closed 2 years ago

briandfoy commented 2 years ago

I'm still trying to track down this problem, but here's what I know so far.

If I specify a requestBody, denote a content type, and set the schema to a string type, the validation thinks there is no body. I'm working on something where the request body is absolutely not a form value and is a simple string but can also be a JSON body, and the client can decide which one to send. This is not something I've designed, just something that is the way it is and isn't changing how it does things.

There was some conversation awhile ago in #31, but there's also this comment:

Please open a new issue if someone wants this module to validate consumes/produces.

The weird part is that this problem doesn't exist if part of the content type in the requestBody is a wildcard, so text/* and */plain, and */* don't show this problem. The fully-specified type doesn't have to be anything in particular, just fully specified. So, application/x-foo in requestBody has the same problem.

use Mojo::Base -strict;
use Test::Mojo;
use Test::More;

use Mojolicious::Lite;

post '/pets' => sub {
  my $c = shift->openapi->valid_input or return;
  $c->render(openapi => $c->validation->output);
  },
  'getPets';

plugin OpenAPI => {url => 'data:///parameters.json'};

my @classes = qw(Mojolicious::Plugin::OpenAPI JSON::Validator);
foreach my $class ( @classes ) {
    say "$class: ", $class->VERSION;
    }

my $t = Test::Mojo->new;

say "=" x 50;
$t->post_ok('/api/pets' => { "Content-Type" => 'text/plain' } => 'Body' )->status_is(200);
say $t->tx->req->to_string;
say '-' x 50;
say $t->tx->res->to_string;

done_testing;

__DATA__
@@ parameters.json
{
  "openapi": "3.0.0",
  "info": {
    "license": {
      "name": "MIT"
    },
    "title": "Swagger Petstore",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "/api"
    }
  ],
  "paths": {
    "/pets": {
      "get": {
        "operationId": "getPets",
        "requestBody": {
           "required": true,
           "content": {
              "text/plain": {
                  "schema": {
                     "type": "string"
                  }
              }
            }
        },
        "parameters": [],
        "responses": {
          "200": {
            "description": "pet response",
            "content": {
              "*/*": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}

And, the output:

Mojolicious::Plugin::OpenAPI: 5.01
JSON::Validator: 5.03
==================================================
ok 1 - POST /api/pets
not ok 2 - 200 OK
#   Failed test '200 OK'
#   at request_body.pl line 24.
#          got: '400'
#     expected: '200'
POST /api/pets HTTP/1.1
Content-Type: text/plain
User-Agent: Mojolicious (Perl)
Content-Length: 4
Host: 127.0.0.1:64682
Accept-Encoding: gzip

Body
--------------------------------------------------
HTTP/1.1 400 Bad Request
Date: Sat, 20 Nov 2021 16:49:05 GMT
Server: Mojolicious (Perl)
Content-Length: 83
Content-Type: application/json;charset=UTF-8

{"errors":[{"message":"Expected string - got null.","path":"\/body"}],"status":400}
1..2
# Looks like you failed 1 test of 2.
jhthorsen commented 2 years ago

I don't think plain string/binary uploads have been very well supported ever. Guess one of the reasons is that I personally use form data instead.

Anyhow, this should be fixed in the upcoming release 👍