I have an ember data model that looks like this (note that I am using typed-ember/ember-cli-typescript)
import DS from "ember-data";
export default class AccountIdentity extends DS.Model.extend({
organizations: DS.hasMany("org/organization", { async: true })
}) {
// normal class body definition here
}
// DO NOT DELETE: this is how TypeScript knows how to look up your models.
declare module "ember-data/types/registries/model" {
export default interface ModelRegistry {
"account/identity": AccountIdentity;
}
}
Note how the response doesn’t contain any organization relationships, and this is because they are on a different service and the account service doesn’t know anything about the org service. But I was hoping i could override the urlForFindHasMany and tell ember data where to load the organizations from. However when I do:
I would advocate restructuring the API response to follow the specification by sending back a “compound document” from your server. ember-data would then load auxiliary records based on the relationships specified in the payload. The “Retrieving Related Model Records” section here gives a usage example.
In your case do you have control over what the payload returned by the account/identities endpoint?
Also, are any organizations loaded already into the store?
@efx I don’t have control over the account service. Also, it is meant to be a generic authorization/authentication service used for many applications, and it isn’t supposed to know which applications.
The org service is one such application, and it knows how the identities and organizations are related within itself.
Now I am writing an ember app for the org service which authenticates against the account service. I was hoping that I could somehow tell ember data to load the organizations from the org service instead of expecting them to be specified on the account/identity resource from the account service.
I suppose I could write a custom serializer for the account/identity model that just sticks a related/self link into the response…but I thought there would be a better way to go about this.
Is org represented as a model in your app? If so I think a findAll using the model name used by the org service could load them as you expect. It seems you would need to load the relationships from whichever service knows about them. Offhandedly I’m not sure how the order of loading models and auxiliary records works so would suggest testing to see.
As an aside you could explore using store.push if you need to load arbitrary JSON:API payloads. But that seems like the same if not more manual work of using a custom serializer.
But I was hoping i could override the urlForFindHasMany and tell ember data where to load the organizations from
If that’s what you’re going for I think all you’d need to do is add relationship “links” in your serializer. The problem is that you are overriding urlForFindHasMany but as far as ED is concerned it doesn’t know that your account is linked to anything, so it doesn’t know it should fetch.
You can link relationship data in multiple ways, like by id (probably the most common) or by links. But ED needs either links or ids to know how/where to look up the relationships and link the records. Typically this information is provided by your API but if it is links and they are able to be generated by data that you already have on the front-end, you can add them in the serializer.
This is what I’ve done in the past. You may be able to import the adapter from the serializer and use that to format the URLs if that is desirable.
// accounts serializer
normalize: function(typeClass, hash, prop){
// add a 'users' link to support our 'hasMany'
hash.links = {
users: `/accounts/${hash.id}/users`
};
return this._super(typeClass, hash);
},
Not crazy at all. I don’t think there’s a “better way to go about this” because I would argue that this way isn’t bad or the least bit unusual. I mean technically an API would/should typically be the single source of truth about data and how it is related, but I think this is a fairly common problem, and this is a very natural way of supplementing information from the API. So I don’t think it should feel weird.
I think the only reason it seems that way is that ED makes everything so easy that a custom serializer seems like “overkill” in a lot of scenarios even if it shouldn’t. ED is an incredibly powerful data layer with a very broad API surface that is intended to be extensible and configurable and this use case fits pretty nicely within those standard APIs. Ember Data itself only covers the most common data use cases (it’s definitely not good for some things), and you can only get so far with “config free” Ember Data. So… all that to say… far from crazy, I think this is actually pretty standard.