Search code examples
ember.jsjson-api

How Do I Construct my Ember Models and API Data to represent data on the relationship?


I'm new to jsonapi and how the structure works and trying to get a relationship to load properly. I'm expecting ember-data to follow provided url's in the relationship.links of my objects to fetch the required information but I'm getting unexpected results.

I have Users, Territories, and a User/Territory relationship defined like this:

// User Model
const UserModel = DS.Model.extend({
    username: DS.attr('string'),
    territories: DS.hasMany('user-territories')
}

// Territory Model
const TerritoryModel = DS.Model.extend({
    name: DS.attr('string')
}

// User-Territory Model
const UserTerritoryModel = DS.Model.extend({
    notes: DS.attr('string'),
    startDate: DS.attr('date'),
    user: DS.belongsTo('user'),
    territory: DS.belongsTo('territory')
}

I then have mock data (using http-mock) that looks like this:

// api/users/
data: {
    type: "users",
    id: 1,
    attributes: {
        username: "thisIsMyUsername"
    }
},
relationships: {
    territories: {
        links: {
            self: "http://localhost:4200/api/users/1/territories"
        }
    }
}

// api/users/1/territories
data: {
    type: "user-territories",
    id: 1,
    attributes: {
        notes: "This is a note",
        startDate: "2017-01-01"
    }
},
relationships: {
    user: {
        link: {
            self: "http://localhost:4200/api/users/1"
        }
    },
    territory: {
        link: {
            self: "http://localhost:4200/api/territories/1"
        }
    }
}

// api/territories/1
data: {
    type: "territories",
    id: 1,
    attributes: {
        name: "Territory #1"
    }
}

In my User route, I want to request the UserModel and have access to the UserTerritory Relationship data and the Territory itself. The api calls are not what I expect though:

this.get('store').findRecord('user', 1, { include: "territories" });

EXPECTED:

  • api/users/1
  • api/users/1/territories

ACTUAL:

  • api/users/1
  • api/users/1?include=territories

If I call the user-territories model I get this:

EXPECTED:

  • api/users/1/territories

ACTUAL:

  • api/user-territories/1

Solution

  • If you use included, ember-data basically thinks you want to tell the server to side-load data. If you return a links, just resolve the relationship. However the relationships have to be inside the data. Also the self link is for the relationship itself, to return the data use related.

    So first you do something like user = store.findRecord('user', '1'), this will fetch to api/users/. Then you should return something like this:

    // api/users/
    {
      data: {
        type: "users",
        id: 1,
        attributes: {
          username: "thisIsMyUsername"
        }
        relationships: {
          territories: {
            links: {
              related: "http://localhost:4200/api/users/1/territories"
            }
          }
        }
      }
    }
    

    Next you do user.get('territories'). This will return a promise, and fetch http://localhost:4200/api/users/1/territories, or whatever was inside that related link. However know, what ember-data will expect you to return user-territories here, because thats what you specified with territories: DS.hasMany('user-territories'). You should know what you directly can model an many-to-many relationship in ember-data without a third table.