Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngResource resolving nested resources

What options are there there for resolving nested resources in ngResource responses?

There have been some related questions about resolving endpoints for nested resource in ngResource, but this question is about when a REST response contains a second resource nested in the collection that is being queried, especially 1-to-1 mappings where you wouldn't have e.g. pets/<id>/owner as its own resource.

Say there are two resources, Pets and Owners:

GET /pets:

[{
  name: 'spark',
  type: 'dog',
  owner: '/owners/3/' # alternatively just '3' or the full object.
}]

As a developer, I sometimes want to query the Owner resource as a whole, sometimes I want to query the Pet resource and then I automatically want to resolve the owner attribute into a resource instance.

This is my current solution:

.factory('Pet', function ($resource, Owner) {
  var Pet = $resource('/pets/:id', {id: '@id'});

  Pet.prototype.getOwner = function () {
    return new Owner(this.owner); // or Owner.get({id: this.owner})
  }

  return Pet;
})

Problems here are many. There's integrity – for one. This implementation, I believe, allows for multiple instances of the same resource. Then there's practicality. You also have additional attributes to keep track of (owner and getOwner(), instead of just owner; possibly setOwner if you want to be able to save the model).

An alternative solution could be built on transformResponse, but it would feel like a hack to include that in every resource that has a nested mapping.

like image 454
lyschoening Avatar asked Oct 16 '13 14:10

lyschoening


2 Answers

I believe this is the exact reason why Martin Gontovnikas created Restangular. He didn't like having to deal with nested $resources in the main angular framework. I think his Restangular solution would fit nicely into your needs. His code is on GitHub here and he's got a nice intro video on youtube here.

Check it out. I think you'll find it does exactly what you want it to do.

like image 152
tennisgent Avatar answered Sep 23 '22 18:09

tennisgent


Update: I ended up working on this for a bit and have started a new angular module, available on GitHub. The answer below is about the Gist I wrote originally.

There doesn't seem to be anything around there like what I have been looking for. I have started an implementation of a solution that only supports get and getList (query) operations. The remaining methods should be trivial to add since I've pretty much kept with the layout of the ngResource module. The Gist for my implementation is below.

https://gist.github.com/lyschoening/7102262

Resources can be embedded in JSON either as full objects that simply get wrapped in the correct Resource model, or as URIs, which get resolved automatically. In addition to embedded resources, the module also supports typical nested resources, either as true parent-child collections (where the resource is only accessible after selecting the parent) or as cross-referenced collection.

Yard = Resource('/yard')     # resource model
Yard.$nested('trees')        # embedded item or list of items

Chair = Resource('/chair')

Yard.$nested('/chair')      # sub-collection without its own model
                             # (for many-to-many)

Tree = Resource('/tree')

# child-collection with its own model
TreeHouse = Tree.$childResource('/treehouse')


yard = Yard.get(1)
# GET /yard/1
# {
#    "uri": "/yard/1",
#    "trees": [
#       "/tree/15",   -- reference, looked-up automatically with GET
#       {"uri": "/tree/16", "name": "Apple tree"} 
#                     -- full object, resolved to Tree instance
#    ]
# }
# GET /tree/16
# {"uri": "/tree/15", "name": "Pine tree"}

yard.chair.getList()
# GET /yard/1/chair
# [{"uri": "/chair/1", ...}, ..]
# -- model inferred from URI

yard.trees[0].treehouse.getList()
# GET /tree/15/treehouse
# [{"uri": "/tree/15/treehouse/1", ...}, ..]
# -- automatically resolved to TreeHouse instance
like image 32
lyschoening Avatar answered Sep 26 '22 18:09

lyschoening