-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor and rework http coercion. #231
Conversation
@STRML Thanks for the patch! |
Just wanted to note that there are some breaking changes here:
|
this.converters.unshift(converter); | ||
this.converters[name] = function(val, ctx) { | ||
// Ignore null/undefined | ||
if (name !== 'array' && val === null || val === undefined) return val; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should probably expand the comment here - I skip 'array'
so that the 'array'
converter has a chance to coerce null/undefined
to []
.
I'll squash when ready - open to discussion on this. |
describe('arguments without a defined type (or any)', function() { | ||
it('should coerce boolean strings into actual booleans', givenMethodExpectArg({ | ||
describe('don\'t coerce arguments without a defined type (or any) in JSON', function() { | ||
it('should not coerce boolean strings into actual booleans', givenMethodExpectArg({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks backwards compat. I understand why this change makes sense, but it also makes things like this impossible in loopback:
GET /todos?filter[where][done]=true
Obviously we need a bit more sophisticated type declaration support... but when you don't even know the structure (eg. a nested property of an object) it gets a bit tricky. I'm open to suggestions to overhaul this type system if it means better support for dynamicly typed queries in URLs. Maybe there is some syntax out there that caries more type information?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only with JSON request bodies, not with querystrings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see... you switched up givenMethodExpectArg
to send JSON.
I think this might be a good basis for strong-remoting v3.0.0. I'd like to be careful and clearly document the breaking changes instead of trying to preserve the old behavior (any sort of type inference) in some unpredictable way. We must support something capable of these type of queries though: GET /todos?filter[where][priority][gt]=100&filter[where][done]=false Right now we do this by inferring the type information. This makes the framework a bit magic, and gives less control to the consumer of the API as well producer. You do have the ability to specify explicit types, but that only works in the obvious cases. So in summary I welcome the changes to type inference. I am also in favor of just removing it entirely. But lets not give up on the simplicity of the query syntax, because the flaw of the implementation. Maybe there is a nice syntax / notation / encoding out there that:
A couple that come close:
|
Here is some food for thought that would extend our current syntax with JSON literals: GET /todos?filter[where][priority][gt]=100&filter[where][done]=false Would become... GET /todos?filter[where][priority][gt]=`100`&filter[where][done]=`false` This would parse to: {
where: {
priority: { gt: 100 },
done: false
}
} We could also limit these values to a subset of JSON to avoid
|
@ritch See https://github.com/strongloop/strong-remoting/pull/231/files#diff-d54d77feb22761cf4ef39576b7edd949R118, I am handling sloppy coercion when no type data is available (formData and querystring). |
Yes I like what you've done... but we are trying to preserve behavior that we should probably just get rid of (sloppy coercion). What if I had the unfortunate name: "Mr. False Undefined Null"? GET /people?filter[where][firstName]=false I don't like the fact that as the API consumer I cannot specify that I mean the literal string "false". Maybe its a silly example, but its something I'd like to get rid of. The type inference / sloppy coercion was an attempt to fix a problem with the query string syntax but from the wrong way.
I think we can land/release this as a minor version.
If this is limited to JSON, we can land/release also as a minor version. When the input is Anyways, we can discuss removing type inference in another issue. |
*/ | ||
Dynamic.getArrayConverter = function(converter, val, ctx) { | ||
if (!Array.isArray(val)) val = this.converters.array(val, ctx); | ||
return val.map(function(v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid this closure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not if we're going to pass ctx
to converter
- and the anon func syntax is still quite a bit faster than bind. It's not async, no chance of a leak here because of vars bound outside the closure.
Yes, this is an unfortunate problem with querystring syntax. This PR is designed to be merged as a minor release as the only behavioral changes it makes should be considered bugs / undesirable behavior. Unfortunately I don't have a good answer for how to do nice querystring syntax with support for nested attributes and some semblance of type. I don't think we should invent one ourselves, though. In general, if the API author properly creates models (say, filter could be an actual user model), this won't be a problem. Otherwise, the author should know that if the input is a deep object in a GET param with no provided type information, he should coerce it to the needed type. |
} | ||
|
||
// Tests sending via querystring - should be sloppy conversions | ||
function givenQSExpectArg(options) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah... missed this. Makes sense.
I've done a second pass review and I don't see anything preventing us from merging this. Though I am a bit nervous that with this large amount of changes to tests that something was missed. @STRML @bajtos any ideas on this? In theory, since this build is green we shouldn't have to worry about @STRML have you run any LoopBack apps / automated tests with this version? |
At this time I have not run any tests outside of the suite with this version. But I am looking forward to the merge so I can remove this code: // FIXME why is strong-remoting sending 'null'???
if (pgpPubKey == null || pgpPubKey === 'null' || pgpPubKey === user.pgpPubKey) return; |
@slnode test please |
OK. I'll run it against some apps to get some more confidence in the BC. |
Looks like the build failed. I don't think it has to do with these changes though. Something weird is going on with json-rpc. |
@slnode test please |
Branch needs to be rebased to pull in the fix from #243 that makes our CI green. |
This fixes a number of subtle bugs and restricts "sloppy" argument coercion (e.g. 'true' to the bool true) to string-only HTTP datasources like querystrings and headers. Fixes strongloop#223 (coerced Number past MAX_SAFE_INTEGER) Possible fix for strongloop#208
3671c44
to
b1037d1
Compare
Rebased. |
@STRML thanks for the PR... this is really great. I'll try and land this today. Need to ensure the top down build is all passing and a couple of examples are failing for unrelated reasons. |
@slnode test please |
@STRML don't be alarmed by the large number of failures - it's a result of me adding an additional level of dependencies to the CI mix and a lot of those modules were added only recently and are still lacking real tests. |
@ritch I don't have a better solution for nice query strings, I am fine with landing this patch as an incremental (non-breaking) enhancement. As for unit-tests, it seems to me that most existing tests remain unchanged and this patch is adding more new tests. I guess it would be nice to run the new tests against the old (current) implementation, to see if there are any unanticipated changes? |
@slnode test please |
Refactor and rework http coercion.
Did this get rebased out of master and force-pushed somehow? |
Additionally, there's more that I'd like to add to this in another PR - for example, |
@bajtos What happened here? I just got snagged by a bug because |
This is weird, I have no idea why 5fdf291 is no longer on the master. @ritch @raymondfeng any ideas? |
@bajtos Why does it take almost two months to get an answer as to why a commit was rebased out and force pushed to loopback's most important dependency? I understand there are some bugs - working through them now - but notification + a revert (and/or new failing tests) would be the correct way to do it, simply rebasing the commit out without notice is unacceptable. |
@STRML it looks like somebody has accidentally run I opened a new PR #265 to verify the patch on CI before landing it again. To prevent this situation from happening in the future, I have configured I apologise for the troubles. |
This fixes a number of subtle bugs and restricts "sloppy"
argument coercion (e.g. 'true' to the bool true) to string-only
HTTP datasources like querystrings and headers.