Check out a free preview of the full Ember 2.x course:
The "Ember-Data" Lesson is part of the full, Ember 2.x course featured in this preview video. Here's what you'd learn in this lesson:

Ember-Data is a persistence library that can be used to define how to interact with your APIs. The key objects of Ember-Data are Model, Store, Adaptor, and Serialize. Mike briefly explains each of the object before moving into the next Exercise.

Get Unlimited Access Now

Transcript from the "Ember-Data" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Mike North: Ember-Data is a persistence library. It manages records and models and application state that you are surfacing to your user. There are four key objects, the store, the adapter, the serializer, and the model. You will have one store and probably more than one of everything else in the leverage app.

[00:00:28] And recently as of a couple months ago, there was a pretty dramatic effort to rewrite some confusing portions of Ember-Data and now things look better than ever. There is standardization around the internal data structures and you can read about the convention that Ember-Data is now aligned with at jsonapi.org.

[00:00:57] But it's essentially a very well thought out schema for RESTful APIs and Ember-Data uses that internally as well. And at a high level what's different about working with every data compared to what we've got now in the app? Is that you're not describing with each effort to fetch data, you're not describing the particulars of how to interact with the API and how to massage the data when it comes back.

[00:01:32] What you're doing instead is at the outside of your project and you're defining the process for interacting with it in general and having the right adapters and mappings in place so that the rest of your app. The parts of your app that deal with transitioning between states. The parts of your app that deal with creating new records, and manipulating them, and working with them.

[00:01:55] They have a much simpler and more uniform surface to work with. And that’s where the complexity of your app exists, it’s in the logic itself, how your application works. And it’s good to take the code that deals with bridging the gap between the API's understanding of data and Ember's understanding of data, that can exist sort of on its own and operate independently.

[00:02:29]
>> Mike North: So, the model is a representation of what you're presenting to the user. Usually, this is something that's persisted. It doesn't have to be. You can create records on the client and then throw them away if you wish. That's not the typical use. Models are defined by two things largely.

[00:02:48] Attributes, which can be of various types and relationships to other models. And in terms of terminology when I say model I'm describing a factory, of records. Records are what a model, they're instances of what a model describes. So here's a simple example of what a model could look like.

[00:03:16] This would live in the models folder and this example I'm calling it book.js and you can see that the book has a string that's a title, it has a date for when it was published, and it has a relationship, a has many relationship to the chapter's model. And this means that, you know, I would expect like a list of IDs here so I know you know which chapters should I fetch to flush this relationship out.

[00:03:52] That's what hasMany describes here. That book has knowledge of chapters and that you can lazily fetch that array and flush it out into an actual object of chapters simply by just accessing this property of each record. So that's a great aspect of Ember-Data that you just say that you have this relationship and then the API request sort of happens under the hood, when it's necessary.

[00:04:26] So the store is the main surface you deal with when creating or finding or destroying records. And the effort here is to have a single place that manages everything, a single place to look and that helps keep the task of synchronizing everything simple. So in our case if we have a GitHub.org and, you know, maybe it's displaying in a couple of different places on the screen.

[00:04:54] You want an update to one of those places, sort of trickle through to everything else that's bound to the same data, and the only way to do this reasonably is to kind of have a single source of truth. And it's worth noting that the major frameworks have all coalesced around this idea of a store as a single source of truth.

[00:05:15] Flux, although, more a philosophy than a piece of software. Flux definitely is built around the concept of a store. And Angular data which is a common persistence framework in Angular. That is very closely tied to Ember-Data and also, you know, store centric. Here's an example of how you use a store to retrieve data.

[00:05:42] The first two methods will send API requests out. The second two methods are, sort of equivalent to the first two, except instead of making the API requests, they will look into the cache Ember-Data's cache to see if there's already knowledge of these entities and it'll return you whatever's in the cache.

[00:06:07] So that would be sort of where to look if you know you already have data loaded.
>> Speaker 2: Is there a method that kind of bridges the gap that it will get it from the cache first if it's there otherwise fetch it?
>> Mike North: No, but the logic is not all that difficult.

[00:06:32] So you can still do it in one line. There is a method to check to see if a record exists without even returning it. And so you could, just use the ternary operator and, you know, do what you need to do there. So, adapters, the role of the adapter is to handle the particulars of making a request, so this includes building the URL, this includes specifying what headers and other AGX options are part of the request that's sent out.

[00:07:08] And ultimately it is what actually initiates the XHR request. So you've seen this word application a lot as a default, as sort of the fallback if nothing else is found and application adapter is in line with that. So, the way that if you request a particular type of record like if we ask for a record of type Post, first Ember will attempt to see if you have a type specific adapter for the post model.

[00:07:45] And that would be in your adapter's folder post.js it would be an adapter with a name that matches the model. If that cannot be found you fall back to application adapter which is sort of the default you know that handles everything without a specific adapter in place and serializers work the same way.

[00:08:06] Look for a type specific first and then you fall back to application.
>> Mike North: Here's an example of what an adapter looks like. And this is actually gonna very closely resemble what I'll build out as we move away from jQuery get and to Ember-Data. You can see here I'm specifying the host by default it is the same host that the app is currently running on so although the localhost 4200 trying to get GitHub data and not find it there.

[00:08:41] So this is all you have to do to change the configuration and start talking to GitHub. And then here I'm overriding the default behavior for building a URL so that I can get the org ID and the link to find the repos for a given org. So serializers, they deal with JSON transformation.

[00:09:12] They deal with bridging the gap between the way that your API models data and the way you have data modeled in your Ember app. And so this is all about normalization and your goal ultimately is to get the API data to the JSON API format. And then Ember-Data will handle the rest.

[00:09:33] It will take your javascript objects and create nice observable instances of your models and really handle a lot for you after that point. But this is the blank you have to fill in the bridge the gap between the two different JSON contracts.
>> Mike North: So this is an example of a serializer.

[00:10:02] You can see that normalizeResponse here is what I'm using. This is a very, this is sort of the, a coarse way of normalizing data. There's a more specific normalization methods that you can fill in. But in this case for what I need to do, like in this case I'm receiving data in a format that is not even conducive to using this other normalization hooks and so I have to take a little bit of a heavy handler approach here.