preaction / Yancy

The Best Web Framework Deserves the Best Content Management System
http://preaction.me/yancy/
Other
54 stars 21 forks source link

POST response fails with "Expected object - got null.", but data is successfully stored #10

Closed Akron closed 6 years ago

Akron commented 6 years ago

I wrote a small example application with Mojo::SQLite, that follows pretty much the Yancy standard receipt:

use Mojolicious::Lite;
use Mojo::SQLite;
use Test::More;
use Test::Mojo;
use Mojo::File qw/tempfile/;

my $db_file = tempfile;

helper sqlite => sub {
  state $sql = Mojo::SQLite->new->from_filename($db_file);
};

plugin Yancy => {
  backend => {
    sqlite => app->sqlite
  },
  collections => {
    people => {
      type => 'object',
      properties => {
        id => {
          type => 'integer',
          readOnly => 1,
        },
        name => {
          type => 'string'
        }
      },
      example => {
        name => 'Philip J. Fry'
      }
    },
  }
};

# Load schema
app->sqlite->migrations->from_string(<<SCHEMA)->migrate;
-- 1 up
CREATE TABLE people (
    id SERIAL,
    name VARCHAR NOT NULL
);
-- 1 down
drop table people;
SCHEMA

get '/' => sub {
  my $c = shift;
  $c->render(inline => <<'TEMPLATE');
% my @people = app->yancy->list('people');
<h1>People!</h1>
<ul>
  % for my $person (@people) {
    <li><%= $person->{name} %></li>
  % }
</ul>
TEMPLATE
};

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

$t->get_ok('/')
  ->status_is(200)
  ->text_is('h1', 'People!')
  ->element_exists_not('ul > li');

$t->get_ok('/yancy')
  ->status_is(200)
  ->text_is('head > title', 'Yancy CMS');

$t->post_ok('/yancy/api/people' => json => {
  name => 'akron'
})->status_is(200)
  ->content_is('');

$t->get_ok('/')
  ->status_is(200)
  ->element_exists('ul > li')
  ->text_is('ul > li', 'akron');

done_testing;

When posting the object to /yancy/api/people in 0.017 (replicating the editor behaviour), the server status is 500 and the response is {"errors":[{"message":"Expected object - got null.","path":"\/"}],"status":500}. However, the data is correctly stored and can be retrieved. Am I doing something wrong?

preaction commented 6 years ago

The error is coming from OpenAPI's validation of the response. There's no ID on the row, so when the data is posted, it can't be retrieved by ID. You likely need to change SERIAL to ROWID.

We could make this error message easier by adding an explicit exception if no ID can be computed for the newly-inserted row.

preaction commented 6 years ago

Okay, I've re-created your schema, but the problem isn't what I said it was. I'm going to have to look closer.

Akron commented 6 years ago

Thanks for investigating! I followed the recipe in Yancy::Backend::Sqlite for the SQL schema. So in case it's wrong, it probably needs to be changed there as well.

preaction commented 6 years ago

Looks like the correct way to access the rowid special field in SQLite is to make a column of type INTEGER PRIMARY KEY. I've fixed the docs in the Yancy::Backend::Sqlite appropriately.

Thanks for the detailed reproduction case!