How Ember Data Loads Async Relationships: Part 3
Greetings! Please read Part 1 and Part 2 before continuing on.
Part 1 explored how Ember Data responds to a few common scenarios. Part 2 discussed some less straightforward examples. Part 3 will examine how to load relationships when the API does not provide data or links.
Let’s revisit a scenario from Part 1. Blog Post #3 doesn’t have a relationships
section and therefore does not have any data
or links
.
1 2 3 4 5 6 7 8 |
|
When attempting to load a relationship with this post, Ember Data will not call any adapter hooks.
1 2 |
|
In this post we will explore a few different ways to deal with this situation.
1. Update your API to include data
or links
Really though, if you have control over the API, it might as well follow the JSON:API spec for fetching relationships.
What if you don’t have the ability to change the API? What if your data is structured such that you need to load relationships a) without knowing a url ahead of time, or b) based on user data? Let’s read on to find a solution!
2. Manipulate the relationships links
or data
Assuming we can’t change our API, and without a relationships
section in the payload Ember Data doesn’t call any of our adapter hooks, we’ll have to make a relationships
section ourselves. This could be done in the adapter or the serializer. Let’s do it in the serializer since the adapter is designed to load data and the serializer is meant to manipulate the loaded data.
Another benefit to putting this logic in the serializer is that we can call this._super
first to make sure that we are already working with the JSON:API structure.
Hard-code links
in the Serializer
app/serializers/post.js
1 2 3 4 5 6 7 8 9 10 11 |
|
This same idea could be done with data
, although I’m struggling to think of a use-case for this.
Move Url Building Logic to the Adapter
One bummer about putting this logic in the post serializer is that usually url configuration happens in the adapter. There is likely to be duplication of concerns because there is logic to build urls in the adapter and the serializer.
To get around this, we can inject links
in the serializer with a sentinal value and build the url in the adapter. That might look something like this:
app/serializers/post.js
1 2 3 4 5 6 7 8 9 10 11 |
|
app/adapters/post.js
1 2 3 4 5 6 7 8 9 10 11 |
|
This example is hard-coded for one case and it wouldn’t be too hard to generalize it to work for any relationship. In fact, this is exactly what ember-data-url-templates does.
Limitations
There are some limitations to this approach. In particular, loading relationships will only work for models that have been run through the serializer. This will not work, for example, with a branch new model created by store.createRecord
, until that record is saved (and the response from the server passed through normalize
).
3. Change Ember Data
Let’s review. We are looking at various strategies for loading relationships with Ember Data when the API does not provide links
or data
in relationships
. The first suggestion is to change the API if possible. If it is not possible to change the API, links
can be injected in the resulting JSON:API structure to mimic an API that does provide these things.
Wouldn’t it be nice, though, if Ember Data supported this use-case natively?
The last approach requires Ember Data to change so that supporting this case is a first-class citizen (this has been proposed before). I’m not sure exactly what that would look like. One reason I wrote this blog series is to move the discussion forward. So, what do you think?