Loopback: REST filter bug

Created on 9 Dec 2016  路  7Comments  路  Source: strongloop/loopback

Bug or feature request

  • [x] Bug
  • [ ] Feature request

Description of feature (or steps to reproduce if bug)

  1. send the following request http://localhost:3000/api/test2s?filter[where][and][0][valid]=true&filter[where][and][1][or][0][name]=test&filter[where][and][1][or][1][deleted]=false
  2. check for the console.log produced by the models https://github.com/matebrandl/REST-filter-test/blob/master/common/models/test.js#L5
  3. The (from REST) filter created where JSON object is invalid.

    Link to sample repo to reproduce issue (if bug)

https://github.com/matebrandl/REST-filter-test

Expected result

{"and":[{"valid":true},{"or":[{"name":"test"},{"deleted":false}]}]}

Actual result (if bug)

{"and":[{"valid":true},{"or":[{"[name]":"test"},{"[deleted]":false}]}]}
note the square brackets around name and deleted

Additional information (Node.js version, LoopBack version, etc)

Node.js version: 5.10.0
LoopBack version: 2.22.0, 3.0.0
There is an sql file for the db: https://github.com/matebrandl/REST-filter-test/blob/master/sql/filter_test.sql

stale

Most helpful comment

@bosco-li I guess we can make the qs.parse options configurable with reasonable defaults in LB.

All 7 comments

@bosco-li anything new on this?

We use qs module to parse such parameters. You probably found a bug in https://github.com/ljharb/qs.

var assert = require('assert');
var qs = require('qs');
var json = {filter: {where: {"and":[{"valid":true},{"or":[{"name":"test"},{"deleted":false}]}]}}};
var x = qs.stringify(json, { encode: false });
var y = qs.parse(x);
console.log('%j %j', json, y);
assert.deepEqual(json, y); // will throw

Can you open an issue against https://github.com/ljharb/qs?

See https://github.com/ljharb/qs/issues/188#issuecomment-268351415 for why this isn't a bug, it's two things: the default depth option of qs.parse, and that there's no safe way to automatically coerce the strings "true" and "false" into booleans.

@bosco-li I guess we can make the qs.parse options configurable with reasonable defaults in LB.

@BenjaminHorn Please note that you can use stringified JSON as the value for filter, for example:
?filter={where: {"and":[{"valid":true},{"or":[{"name":"test"},{"deleted":false}]}]}}

@raymondfeng I am aware of that, but I still want to use the more common REST filter format.

Hey!
I ran into this same 'issue' and wanted to give my thoughts for it. I understand the parsing of the query is done with qs library and that there's no safe way to convert string to booleans, at least not without the context. However, it anyway seems to partly work with Loopback already.

I have the following:

Model property: "soldSeparately": { "type": "boolean" }
Example value: { soldSeparately: true }
Example query: ?filter[where][soldSeparately]=true // Works, 'true' seems to be converted to boolean

Model property: "amenities": { "type": "object" }
Example value: { amenities: { jacuzzi: true }}
Example query: ?filter[where][amenities.jacuzzi]=true // Does not work, value remains as a string

So I guess there even is some kind of conversion in Loopback already or does this just happen to work?
Anyways, since we know that soldSeparately is a type of boolean, I guess it would be possible to check the filter pointing to that property and convert the value accordingly based on the type (if it's not done already).

For the amenities object of course we couldn't do that directly. However, I tried to change the object to be a embedsOne relation so that each property was defined separately to be a boolean, and the same query still didn't work, even though I would've assumed it should have, since the soldSeparately was working like that as well.

Was this page helpful?
0 / 5 - 0 ratings