5
votes

I'm using EmberJs and Ember-Data in a Google App Engine project which uses NDB. In the database I have Host, Probe and Check entities. The database model doesn't really matter as long as I have my REST api in order but for clarity here are my database Classes:

class Host(ndb.Model):
    hostName = ndb.StringProperty()

hostKey = ndb.Key('Host', 'SomeHostId')

class Probe(ndb.Model):
    checkName = ndb.StringProperty()

probeKey = ndb.Key('Host', 'SomeHostId', 'Probe', 'SomeProbeId')

class Check(ndb.Model):
    checkName = ndb.StringProperty()

checkKey = ndb.Key('Host', 'SomeHostId', 'Probe', 'SomeProbeId', 'Check', 'SomeCheckId')

I've added the keys in order to show that each host has some probes running on them and each probe performs some checks.

  • Host
    • Probe
      • Check

In my App.Js I have defined the following models:

App.Host = DS.Model.extend({
    hostName: DS.attr('string')
    probes: DS.hasMany('probe',{async:true})
});

App.Probe = DS.Model.extend({
    host: DS.belongsTo('host'),
    probeName: DS.attr('string')
    checks: DS.hasMany('check',{async:true})
});

App.Check = DS.Model.extend({
    probe: DS.belongsTo('probe'),
    hostName: DS.attr('string')
});

I have defined the following router:

App.Router.map(function() {
    this.resource('hosts', function(){
        this.resource('host', { path:':host_id'}, function(){
            this.resource('probes', function(){
                this.resource('probe', { path:':probe_id'}, function(){
                    this.resource('checks', function(){
                        this.resource('check', { path:':check_id'}, function(){

                        });
                    });
                });
            });
        });
    });
});

And in AppEngine if have built the following URL paths:

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    webapp2.Route('/hosts', HostsHandler),
    webapp2.Route('/hosts/<hostId>/', HostHandler),
    webapp2.Route('/hosts/<hostId>/probes', ProbesHandler),
    webapp2.Route('/hosts/<hostId>/probes/<probeId>/checks', ChecksHandler),
    webapp2.Route('/hosts/<hostId>/probes/<probeId>/checks/<checkId>/', CheckHandler)
])

http://example.com/hosts returns:

{
    "hosts": [
        {
            "hostName": "SomeHostName1",
            "id": "SomeHostId1"
        },
        {
            "hostName": "SomeHostName2",
            "id": "SomeHostId2"
        }
    ]
}

http://example.com/hosts/SomeHostId1/probes returns:

{
    "probes": [
        {
            "probeName": "SomeProbeName1",
            "id": "SomeProbeId1",
            "host_id": "SomeHostId1"
        },
        {
            "probeName": "SomeProbeName2",
            "id": "SomeProbeId2",
            "host_id": "SomeHostId1"
        }
    ]
}

http://example.com/hosts/SomeHostId1/probes/SomeProbeId1/checks returns:

{
    "checks": [
        {
            "checkName": "SomeCheckName1",
            "id": "SomeCheckId1",
            "probe_id": "SomeProbeId1"
        },
        {
            "checkName": "SomeCheckName2",
            "id": "SomeCheckId2",
            "probe_id": "SomeProbeId1"
        }
    ]
}

My templates are:

<script type="text/x-handlebars" id="host">
  <h3>{{hostName}}</h3>
  {{#link-to 'probes' probes}}probes{{/link-to}}

  {{outlet}}
</script>

<script type="text/x-handlebars" id="probes">
  {{#each probe in probes}}
    Probe: {{probe.probeName}}
    {{#link-to 'checks' probe.checks}}checks{{/link-to}}
  {{/each}}

  {{outlet}}
</script>

<script type="text/x-handlebars" id="checks">
  {{#each check in checks}}
    Check: {{check.checkName}}
  {{/each}}
</script>

Now I have all this... but no clue how to tie it up together so that Ember-Data makes the right http requests. So far I've only seen request go to http://example.com/modelName/

3

3 Answers

3
votes

Currently Ember Data does not support this type of nested routes for API endpoints. There's been some talk about this, but it doesn't seem to be making any forward progress.

3
votes

I don't know anything about App engine, but if you could obtain a config like this, for ember-data rest adapter

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    webapp2.Route('/hosts', HostsHandler),
    webapp2.Route('/hosts/<hostId>', HostHandler),
    webapp2.Route('/probes', ProbesHandler),
    webapp2.Route('/probes/<probeId>', ProbesHandler),
    webapp2.Route('/checks/', CheckHandler)
    webapp2.Route('/checks/<checkId>/', CheckHandler)
])

And the response to http://example.com/hosts should return a json array hosts:[{},{}] and to http://example.com/hosts/1 a json representing a host object host:{} and the same for the other AppEngine routes

2
votes

You have defined the Host model twice, I think that shouldn't have been the case. I am pretty new to ember and haven't used async:true feature, but I have been able to do things like(but I hadn't used nested route):

App.Host = DS.Model.extend({
    hostName: DS.attr('string')
    probes: DS.hasMany('probe')
});

App.Probe = DS.Model.extend({
    probeName: DS.attr('string')
    checks: DS.hasMany('check')
});

App.Check = DS.Model.extend({
    checkName: DS.attr('string')
});

and you can spin up a rest api for host that returns :

{
    "hosts": [
        {
            "hostName": "SomeHostName1",
            "id": "SomeHostId1",
            "probes":["p1","p2"]
        },
        {
            "hostName": "SomeHostName2",
            "id": "SomeHostId2",
            "probes":["p2","p3"]
        }
    ],
    "probes": [
        {
            "probeName": "SomeProbeName1",
            "id": "p1",
            "checks":["c1","c2"]
        },
        {
            "probeName": "SomeProbeName2",
            "id": "p2",
            "checks":["c2","c3"]
        }
    ],
    "checks": [
        {
            "checkName": "SomeCheckName1",
            "id": "c1"
        },
        {
            "checkName": "SomeCheckName2",
            "id": "c2"
        }
    ]
} 

In my case I didn't have nested route but I think we should be able to set the controller content from the master payload somehow since all the required content are in store already! I don't know if it was of any help, but this is something I would also like to know the answer of.