jhthorsen / mojolicious-plugin-openapi

OpenAPI / Swagger plugin for Mojolicious
54 stars 44 forks source link

Posting an Array of Objects as a body parameter not supported in OpenAPI v2 #240

Closed lafokamotion closed 1 year ago

lafokamotion commented 1 year ago

Similar issue to https://github.com/jhthorsen/mojolicious-plugin-openapi/issues/219

Except the body parameter is an array of objects containing a string as shown:

parameters:
  - name: echo
    in: body
    description: Text that should be echoed
    schema:
      type: array
      minItems: 1
      items:
        type: object
        required:
          - record
        properties:
          record:
            type: string

The idea being that we have a service that can take one or more items in a POST, shouldn't the spec be able to accept a json object such as:

[ { record => 'foo' }, { record => 'bar' } ]

However, when calling $c->openapi->valid_input(), the following message is received:

{
      errors => [
                  {
                    message => "Expected object - got string.",
                    path => "/echo/0",
                  },
                ],
      status => 400,
    }

This also is not an issue for OpenAPI v3 as I've tested the behavior there too.

Perl module versions:

lafokamotion commented 1 year ago

Borrowed a sample from https://github.com/jhthorsen/mojolicious-plugin-openapi/issues/219 to do some testing. Here is the test case, switching between v2 and v3 as well for gits and shiggles:

#!/usr/bin/env perl
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
use Mojolicious::Lite;

post '/echo' => sub {
    my $c = shift->openapi->valid_input or return;
    $c->render(text => $c->req->body);
}, 'echo';

plugin('OpenAPI' => {url => "data:///v2.yaml"}); # or v3.yaml

my $t = Test::Mojo->new;
my $json = [{ record => "foo" }, { record => "bar" }];

$t->post_ok('/v1/echo' => $json)->status_is(200)->content_is($json);

done_testing();

__DATA__
@@ v2.yaml
swagger: '2.0'
info:
  version: 0.0.1
  title: Echo API
basePath: /v1
paths:
  /echo:
    post:
      summary: Echo the thing
      description: This endpoint echos the thing
      operationId: echo
      x-mojo-name: echo
      consumes:
        - application/json
      parameters:
        - name: echodata
          in: body
          description: Payload that should be echoed
          schema:
            type: array
            minItems: 1
            items:
              type: object
              required:
                - record
              properties:
                record:
                  type: string
      responses:
        '200':
          $ref: '#/responses/response200_ok'
responses:
  response200_ok:
    description: Successful response
    schema:
      type: string

@@ v3.yaml
openapi: 3.0.1
info:
  title: Echo API
  version: 0.0.1
servers:
- url: /v1
paths:
  /echo:
    post:
      summary: Echo the thing
      description: This endpoint echos the thing
      operationId: echo
      requestBody:
        description: Payload that should be echoed
        content:
          application/json:
            schema:
              minItems: 1
              type: array
              items:
                required:
                - record
                type: object
                properties:
                  record:
                    type: string
        required: false
      responses:
        200:
          description: Successful response
          content:
            '*/*':
              schema:
                type: string
      x-mojo-name: echo
      x-codegen-request-body-name: echodata
components:
  responses:
    response200_ok:
      description: Successful response
      content:
        '*/*':
          schema:
            type: string
lafokamotion commented 1 year ago

I was able to get this working again with an older version of JSON::Validator and Mojolicious::Plugin::OpenAPI:

Perl module versions: Mojolicious: 9.30 Mojolicious::Plugin::OpenAPI: 3.41 JSON::Validator: 4.25

JSON::Validator > 4.25 will return an error that object method "_resolve" can't be located via JSON::Validator::OpenAPI::Mojolicious.

Mojolicious::Plugin::OpenAPI < 4.00 will pass the code sample.

jhthorsen commented 1 year ago

Sorry for the late reply.

You're not posting JSON in your test case:

- $t->post_ok('/v1/echo' => $json)->status_is(200)->content_is($json);
+ $t->post_ok('/v1/echo', json => $json)->status_is(200)->content_is($json);

There's something strange going on with your setup, since JSON::Validator::OpenAPI::Mojolicious have been removed a long time ago: https://github.com/jhthorsen/mojolicious-plugin-openapi/commit/1adbaca4fcfe9684aba3bffa816cb21ad3680bff

jhthorsen commented 1 year ago

Regardless of my feedback, I found a bug which should be fixed in v5.08.

https://github.com/jhthorsen/json-validator/commit/96672ed1c3a4c05ee13783c3de15b7fc59c97be3

lafokamotion commented 1 year ago

Oh whoops, sorry about that. I'd probably been looking at my own code so long, i missed that syntax. Thanks for your help though!