Skip to content
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

Loopback standard model REST endpoints automatically round BIGINT params #2352

Closed
stevegaossou opened this issue May 18, 2016 · 7 comments
Closed

Comments

@stevegaossou
Copy link

stevegaossou commented May 18, 2016

Summary

This one is causing me a lot of pain.

After a lot of debugging it looks like Loopback is automatically assuming an ID value on the URI (e.g. /api/myModel/:id) is a Number.

So something like this:
curl -X GET --header "Accept: application/json" "http://192.168.99.100:3000/api/profiles/5828128208445124611"

Does not work because Loopback is automatically converting the BIGINT value to Number, which rounds 5828128208445124611 to 5828128208445125000.

So the above GET request example, results in an error:

{
  "error": {
    "name": "Error",
    "status": 404,
    "message": "Unknown \"Profile\" id \"4828128208445124611\".",
    "statusCode": 404,
    "code": "MODEL_NOT_FOUND",
    "stack": "Error: Unknown \"Profile\" id \"4828128208445124611\".\n    at Function.convertNullToNotFoundError (/usr/src/app/node_modules/loopback/lib/persisted-model.js:81:17)\n    at invokeRestAfter (/usr/src/app/node_modules/loopback/node_modules/strong-remoting/lib/rest-adapter.js:453:25)\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:607:21\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:246:17\n    at iterate (/usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:146:13)\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:157:25\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:248:21\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:612:34\n    at interceptInvocationErrors (/usr/src/app/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:681:22)\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:154:25\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:154:25\n    at /usr/src/app/node_modules/loopback/node_modules/async/lib/async.js:154:25\n    at execStack (/usr/src/app/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:488:7)\n    at RemoteObjects.execHooks (/usr/src/app/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:492:10)\n    at phaseAfterInvoke (/usr/src/app/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:652:10)\n    at runHandler (/usr/src/app/node_modules/loopback/node_modules/loopback-phase/lib/phase.js:135:5)"
  }
}

Enabling debugging output in Loopback shows:

Tue, 17 May 2016 19:52:05 GMT loopback:connector:postgresql SQL: SELECT "user_id","first_name","last_name","email","phone","created_at","updated_at","created_by","updated_by" FROM "user_profile"."profile" WHERE "user_id"=$1 ORDER BY "user_id" LIMIT 1
Parameters: ["4828128208445125000"]

So clearly the value 4828128208445124611 gets rounded into 4828128208445125000.

I verified that this happens right at the beginning, using an operations hook:

  Profile.observe('access', function logQuery(ctx, next) {
    console.log('Context', ctx);
    next();
  });

The output shows the ID is already truncated:

query:
 { where: { userId: '4828128208445125000' },
   limit: 1,
   offset: 0,
   skip: 0 },

Is this a known issue? I couldn't find documentation or bug reports etc. on this.

Custom Remote Method

Btw, adding my own remoteMethod where I have control over the Input Argument (i.e. forcing it to be a string) and then calling findById programmatically works correctly:

  Profile.get = function(id, cb) {
    console.log('ID:', id);
    Profile.findById(id).then(function(profile) {
      console.log('FindById: profile', profile);
      cb(null, profile);
    });
  };
  Profile.remoteMethod(
    'get',
    {
      accepts: [
        {arg: 'id', type: 'string', required: true}
      ],
      http: {path: '/:id/get', verb: 'get'},
      returns: {arg: 'profile', type: 'object'}
    }
  );

You can see above I simply am copying the default findById REST endpoint, only difference is I add get to the end of the URI /api/profiles/:id/get. The logic just defers to Profile.findById().

Calling it:

curl -X GET --header "Accept: application/json" "http://192.168.99.100:3000/api/profiles/4828128208445124611/get"

Works with no issues.

@stevegaossou
Copy link
Author

Looks like this is the same issue as #1870 which is supposed to be fixed by #1221.

@richardpringle
Copy link
Contributor

@raymondfeng are there still plans to land #1221? Maybe someone else should take it over if not.

@bajtos, is this related to coercion clean-up in strong-remoting? Do you have any PRs that fix the issue?

@bajtos bajtos added this to the #Epic: Coercion Cleanup milestone Jun 8, 2016
@bajtos
Copy link
Member

bajtos commented Jun 8, 2016

@richardpringle I think it may be related to coercion clean-up, thank you for pointing it out!

@bajtos
Copy link
Member

bajtos commented Sep 13, 2016

This problem has been fixed by #343 in LoopBack 3.0 (alpha). When converting "any"-typed argument from a string-source like a query string, we preserve string values that are too large to store in an integer (greater than MAX_SAFE_INTEGER).

@bajtos bajtos closed this as completed Sep 13, 2016
@lukewendling
Copy link

@bajtos Any chance this can this be backported to 2.x? We've been bitten by this a couple of times.

@bajtos
Copy link
Member

bajtos commented Nov 2, 2016

@lukewendling @justinlueders
I am afraid there is no easy way how to backport the fix to 2.x, as the coercion code was completely rewritten in 3.0.

I think this is the place where to fix the problem in 2.x, if you feel like contributing the fix yourself:
https://github.com/strongloop/strong-remoting/blob/c88d61c3334bcc64e94727bf482904900f134590/lib/http-context.js#L298

@idandeshe
Copy link

idandeshe commented Jan 11, 2019

I am using version loopback ver 3.22.0 with loopback-connector-mssql ver 3.3.0.
when setting a model properties as the following:

"objectId": {
"type": "Number",
"id": true,
"generated": true,
"required": false,
"length": null,
"precision": null,
"scale": null,
"mssql": {
"columnName": "objectId",
"dataType": "bigint",
"dataLength": null,
"dataPrecision": null,
"dataScale": null,
"nullable": "NO"
}

(notice the "id":true and "dataType": "bigint")
LB round the BIGINT params.

Changing the id property to false fixes the issue, but loopback does not allow models with no id when connecting a DB, I used a very unprofessional work around at the moment)

Is this issue still marked as an open bug?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants