You get a JSON response from the server, but it’s not quite what you want? Bring out normalizeResponse, Ember Data Serializer’s swiss army chainsaw of normalization methods.
Links
Code
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType){
if(payload.data.length >= 0) {
payload.data.forEach((book)=>{
book.type = 'book';
})
} else {
payload.data.type = 'book'
}
return this._super(...arguments)
}
});
A more concise way of writing this, contributed by John Molina in the comments:
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
normalizeResponse(store, primaryModelClass, { data }, id, requestType){
if(Em.isArray(data)) {
data.setEach('type', 'book')
} else {
data.type = 'book'
}
return this._super(...arguments)
}
});
Transcript
In the last episode, we went over the JSON API format. Now this format is what Ember data uses internally, and if you’re using the JSON API serializer, then it’s what you’ll expect to have come over the wire. We are currently using JSON API serializer, but what we’re talking about in the next couple of episodes should be able to be used with a couple of slight variations if you’re using the REST serializer as well or the active model serializer.
So for our challenge today, we’re going to deal with an error in our JSON API. Well, maybe not an error but something that deviates from the form. So here’s a well-developed JSON API. Notice it has type
of books. But now, thanks to a clerical error, these are coming back with the type
kindling. And we want to make sure to still interpret them as books. And by the way, if we reload the page, it will error. So we’ll know we’ve solved this problem when it no longer errors and it shows us our books again.
So to start with, we’re going to use normalizeResponse
. This is what gets called whenever we get the entire response. And so this is... it’s not very subtle, but you can do just about anything you need to do here. So it takes five arguments. These are the store
, and the primaryModelClass
, then the payload
, this is going to be the important one, and the id
and the requestType
. And so we’ll go ahead and stick a debugger
here so that we can see what we’re getting for these.
So here we’ve got our debugger, and the store
of course is just our store, the primaryModelClass
that we’re getting is book. The id
, we’ll go ahead and do that next, is null
since it’s an array. And the requestType
is findAll
, since that’s what we used to get this. But the one that’s really interesting to us is payload
. So the payload it’s getting a data
array and an included
array. So the payload is basically this. So we can dig deeper and see that the payload.data
... we’ll go ahead and grab the first one off of here and we’ll see that it has the type of kindling. And if we let that type stay as it is, then Ember data is not going to know what to do with it, so we need to turn that into type
book.
So what we’ll do is do payload.data
, and then we’ll loop over that with a forEach
. And here we go, and we’ll do book.type = 'book'
. So that’ll loop through and it’ll change our payload. And then we can go ahead and we’ll make sure to return
super and give it [03:45] arguments
, and that will include the updated payload. So we need to reload this and then we can see it working. Great job.
But if we investigate further, we’ll see that it’s not quite completely working yet. If we click on one of these, it’ll show up, but it’s giving us an error here. So why is it doing that? Let’s go ahead and put a debugger here to discover why. So here we reach it the first time and since I already know the answer, I’m going to go ahead and skip ahead. And oh-oh, it looks like we’re reaching it a second time. That’s because in here, in the show page, it’s calling a findRecord
, and so it’s getting a different response here. So store primaryModelClass
and request... requestType
will be different. And then id
... it will have an id
instead of null
. And then of course payload.data
is not an array. And so that’s why it was giving us the forEach
error, because this object does not have a forEach
method.
So we’ll want to find a way to differentiate this. And we could theoretically do it on the requestType
, but as we’ll see later that’s a bit too specific. And maybe we could do it on the id
, but I’m not sure that would get exactly what we want. What we’ll do instead is do it based on whether it’s an array or not. So we’ll test that by doing payload.data
, and make sure the length
is greater than 0. And of course an object doesn’t have any lengths. So there you go. Actually, let’s do greater or equal to 0, so an array with length of 0 will still get put in the array category.
So we’ll have that, and then we’ll need to know what to do with the rest of them, and it’s actually fairly simple. Just, since it’s just an object, we’ll put the one type
there. So we change that one type on the single object, and then we call super
no matter what. And let’s see if this is working. Yes. Great job everyone, no errors.
So we solved our problem and we did it using normalizeResponse
, but normalizeResponse
is sort of the Swiss Army chainsaw of serializer methods, as in yes it can do exactly what you want, it can do almost anything you want, but it can be hard to read and if we had more complications, you could see how this could get out of control very quickly.
So in the next episode, we’re going to go over some methods that are easier to read, easier to understand, and when things get real complicated, easier to keep disentangled. So we’ll go over some of them that we’ll use to specifically disentangle this normalizeResponse
and then we’ll go over them in general so that you can extrapolate that to the other normalize
methods that you may want to use. I’ll see you then.
- Ember Data 2.0-Getting Started, and Basics of DS.Model
- Ember Data 2.0-Getting Data from the Server with findRecord and findAll
- Ember Data 2.0-Store Manipulation with Peek, Unload, and More
- Ember Data 2.0-Create, Save, and Destroy Records
- Ember Data 2.0-Updating Data, Tracking Changes, and Rolling Them Back
- Ember Data 2.0-Metaprogramming with DS.Model Attributes Property
- Ember Data 2.0-Model States and Flags
- Ember Data 2.0-states.js Deep Dive
- Ember Data 2.0-Relationships
- Ember Data 2.0-Metaprogramming with Relationships
- Ember Data 2.0-Overview of using Adapters and Serializers
- Ember Data 2.0-Overview of Customizing Adapters and Serializers
- Ember Data 2.0-Essential Adapter Customizations
- Ember Data 2.0-Advanced Adapter Customizations
- Ember Data 2.0-Miscellaneous Adapter Customizations
- RESTAdapter vs JSONAPIAdapter vs ActiveModelAdapter
- Introduction to Serializers
- JSON API
- Serializers-normalizeResponse
- Serializers-normalize${specific}Response
- Serializers-How are normalize and normalizeResponse different?
- Serializers-Extracting Attributes and IDs
- Serializers-Extracting Relationships
- Serializers-keyForAttribute and keyForRelationship