Series: Introduction to Ember Data 2.0

Serializers-normalizeResponse

Published on Apr 20, 2016

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.

Introduction to Ember Data 2.0

Subscribe to our mailing list