Enable nestRemoting for more than 2 levels (for nested queries)

236 views
Skip to first unread message

Akram Shehadi

unread,
May 30, 2016, 1:04:14 AM5/30/16
to loopb...@googlegroups.com

My question is basically is, how can I enable nestRemoting (nested queries for related models) for more than 3 related models?

Currently I am working with 4 related models and would like to be able to do nested queries all the way up or down, and right now I am only able to do so for 3 models (i.e. 2 levels up and 2 levels down).

What works:

So for example, I have my Account model which is the root of everything, i.e. all other models eventually lead to an Account) and then I have let's say Projects, Folders then Photos as leaves.

I already configured my relations and it works perfectly fine, e.g.

  • Account hasMany Projects
  • Project hasMany Folders
  • Folder hasMany Photos

and the other way around as well:

  • Photo belongsTo Folder
  • Folder belongsTo Project
  • Project belongsTo Account

and finally in my code I added:

// Configure one way of the relation
Account.nestRemoting('projects');
Project.nestRemoting('folders');
Folder.nestRemoting('photos')

// Configure the other way of the relation
Photo.nestRemoting('folder')
Folder.nestRemoting('project')
Project.nestRemoting('account');

This works wonderful and lets me do things like

/api/Accounts/<account id>/projects/<project id>/folders

To get a list of Folders that belong to that Account.

And viceversa, I am able to do the other way around:

/api/Photos/folder/project/

However:

When I try to add one more nested level to the query in either direction I get an error.

I.e. if I try to do

/api/Accounts/<account id>/projects/<project id>/folders/<folder id>/photos

or if I do

/api/Photos/folder/project/account

I get the following error:

"name": "Error",
"status": 404,
"message": "Shared class \"Account\" has no method handling GET /<uuid>/projects/<uuid>/folders/<uuid>/photos?access_token=XXXXXXXXXXXXXXX",
"statusCode": 404,
"stack": "Error: Shared class \"Account\" has no method handling GET /<uuid>/projects/<uuid>/folders/<uuid>/photos?access_token=XXXXXXXXXXXXXXX\n    at restRemoteMethodNotFound (/myserver/node_modules/loopback/node_modules/strong-remoting/lib/rest-adapter.js:322:17)\n    at Layer.handle [as handle_request] (/myserver/node_modules/loopback/node_modules/express/lib/router/layer.js:95:5)\n 

(I replaced the actual id for for redability)

But this error is only triggered when I try to query more than 2 levels above the model (or 2 levels below).

So for example if I start one level below (e.g. at Project instead of Account):

/api/Projects/<project id>/folders/<folder id>/photos

This works fine.

Or the other way around:

/api/Folders/project/account

That tells me that the methods and everything is working as expected but there is a limit on the nesting levels.

If I enable strong-remoting strings I get the following:

- For the version that does work 

/api/Accounts/<account id>/projects/<project id>folders/<folder id>

strong
-remoting:rest-adapter Invoking rest.after for Account.prototype.__findById__projects__folders +1ms

- But if I add the last level, i.e. 'photos' I get:

/api/Accounts/<account id>/projects/<project id>folders/<folder id>/photos

strong-remoting:rest-adapter Error in GET /
Accounts/1b8771ea-4379-4faf-b2ed-15dbde4b626b/projects/98d0bc9e-5008-4d09-9be0-5d194bd894b2/folders/af4a9dab-12f4-450d-87ee-13110e2da602/photos?access_token=CcJHHxvzLH0dzcaJoMOG7xC7EoITHUxJGnGHR3bKYh665Nb0UdsS0xYCLdqXpUgH: Error: Shared class "Account" has no method handling GET /1b8771ea-4379-4faf-b2ed-15dbde4b626b/projects/98d0bc9e-5008-4d09-9be0-5d194bd894b2/folders/af4a9dab-12f4-450d-87ee-13110e2da602/photos?access_token=CcJHHxvzLH0dzcaJoMOG7xC7EoITHUxJGnGHR3bKYh665Nb0UdsS0xYCLdqXpUgH
    at restRemoteMethodNotFound
(/myserver/node_modules/loopback/node_modules/strong-remoting/lib/rest-adapter.js:322:17)
    at
Layer.handle [as handle_request] (/myserver/node_modules/loopback/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix
(/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:312:13)
    at
/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:280:7
    at
Function.process_params (/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:330:12)
    at
next (/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:271:10)
    at
Function.handle (/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:176:3)
    at router
(/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:46:12)
    at
Layer.handle [as handle_request] (/myserver/node_modules/loopback/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix
(/myserver/node_modules/loopback/node_modules/express/lib/router/index.js:312:13) +6s

It seems that for some reason it's not registering the full dependency path, but searching the code I couldn't find a hard limit that would stop at 3 levels deep.

So back to my original question, how can I add more levels to a nested query? is there anything I can config without modifying loopback's source code?

By the way, my datasource is a MongoDB instance (i.e. mongodb connector)

Edit: Someone posted this GitHub issue which shows that this is an unsupported feature and not a bug, so I guess I have to either fix it myself or look for a workaround. However any other pointers on how to achieve this or how exacly does the nestRemoting logic works is appreciated.


Thanks!

Paddy Mann

unread,
May 31, 2016, 2:19:59 AM5/31/16
to LoopbackJS
Hej Akram,

As you spotted - I've already raised a GitHub issue. It's a surprisingly limitation of Loopback currently, though I'm unclear on the reason for it. It feels to me as the original architecture didn't really consider having more than 2 levels deep, and nestRemoting was a hack to get it to three. But even that hack works in a different way to just having 2 levels deep and has limitations (see the GitHub issue) :(

For now, I am resorting to (e.g.) making calls to /projects/<project id>/folders/<folder id> rather than /Accounts/<account id>/projects/<project id>/folders/<folder id>, and creating a new role resolver to handle accessing the project at the root level rather than the account

This workaround only gets me one layer deeper and I'm still going to hit more stumbling blocks. I'd be very interested in the workarounds you come up with - please share in the GitHub issue :)

Paddy

Akram Shehadi

unread,
May 31, 2016, 11:18:18 AM5/31/16
to LoopbackJS
Hi Paddy,

Yes, that's also what I am going to do. 

Also, I do think that extending to more than 2 levels is not that hard (in terms of the architecture).

I was thinking that since we have access to the modelFrom, modelTo and the relations for both, we could just try to do a recursive search where after adding all methods for the models in "relations" array, we basically would just need to get the model from the nestedFn variable, and do the same all over again.

I haven't had the time to write this all up but that's the basic idea. Although not sure if this would be idiomatic Loopback.

The truth is that in the end we will probably need a proper dependency traverse because we still need to avoid certain relations maybe (e.g. hasManyThrough, not sure how would that work)

I'll try to write my findings in the issue whenever I can.

Thanks!
Akram

Ganesh B

unread,
Apr 22, 2018, 12:35:22 AM4/22/18
to LoopbackJS
Hi,

A quick question: I have nest APIs for belongsTo as true. How do I reference nested APIs for disabling method or adding ACLs? First level access using prototype.__create__orgGroups for GET /Orgs/{id}/orgGroup works fine. But the Second level nested API access for belongsTo relation using prototype.__create__orgGroups_Orgs or prototype.__create__orgGroups__get__Orgs for GET /Orgs/{id}/orgGroup/Orgs does not work.

Any help with how to access the method name?

Regards,
Ganesh
Reply all
Reply to author
Forward
0 new messages