 So it's great to be here. It's my third time here as an attendee, but my first time as a presenter. And I have to tell you, this is a completely different perspective from the side of the stage. So maybe you should try it next year. It's really great. OK, so I'm going to talk about data loading patterns with just an API, a live magic move. And so this talk is going to be a series of use cases that I think are very prevalent in Ember apps. And there's going to be a lot of code involved. So don't say I didn't warn you. And I hope that by the end of the presentation, you will have an added sense of confidence in tackling these scenarios. And I also hope that I spare some discussion about some of these, because I think that it's really important to just engage in discussion. It's not a trivial topic. So why JSON API first? Well, instead of going into a detailed explanation of all the advantages that JSON API brings you, let me just tell you a story that happened about a month ago. I started a Greenfield project with a team. And so the backend developer asked me, so what kind of API are we going to use for this project? And I said, let's use JSON API. And then we agreed that we can start a project. There was nothing more to discuss. So of course, down the line, there are going to be things to discuss and agree on, of course. But I really think of JSON API as the convention over configuration for APIs. So in this sense, I think it's really similar to Ember, because it does reduce the number of decisions that you have to make. And I think that's probably the biggest advantage that it has. So to be able to make sense of the examples that follow, I want to make sure that we understand a few things about how Ember data and Ember works. So let's cover these basic things. So in Ember data, you have the store that you mostly interface with. You want to load data. And if the find record, you pass it a type and an ID. And if that record is already in the store, you get it back right away. And then Ember data does a refatch of that record in the background. And if it's not in the store, then you get back a promise. That's eventually going to be resolved with that record. With find all, if there is at least one instance of that time that you are passing in a store, then you get back all of them, all of those that are already in the store. And otherwise, again, you receive a promise that's eventually going to be resolved with all of the records or everything that the backend returns. The peak methods are different. So with peak record, and of course, again, a type and an ID, a peak will never do a request to the backend. So that's the main difference between peak and find methods. So if it's already in the store, you get it back. If it's not in the store, you get no. And with peak all, you get back all the records that are already in the store of that type. And again, never triggering a reload. So that's true by default, I should say. So because there are two flags that affect this behavior, they should background reload record and should background reload all. And so they are true by default. So Ember data will make these background fetches that I mentioned, but you can set them and you can even set them per type because they are configured on the adapter. Just something to keep in mind. About Ember, it's just I want to make sure that you understand nested routes and the model hook. So if you have these routes, the main thing to know is that they are always top down. So the parent route is always fully resolved before entering the child route. They're going to leverage this in the examples. And the other thing is that the model hook has this blocking behavior. If you return a promise from the model hook, then it's not going to render the corresponding template until that promise resolves. And all these methods that we saw find record find or even query, they all return promises. So they are very natural fit to put these two together if you want this blocking behavior. And the app that I'm going to show these examples on is a music catalog app that some of you might already know. So it has a list of bands on the left and then the next level, the bands.band route, we just render that tab navigation and then finally the songs route. We render everything else on the list of songs, those buttons to sort the songs and the search box. And the routes are nested as below. So a little bit more about myself. I'm Balint Erdi on Twitter, I'm B-A-A-Z. And I have a personal site and blog at balinterdi.com. I work as an AmberJS consultant. And I'm also the author of the Rock and Roll with AmberJS book that's meant for developers who want to conquer the Amber learning curve. Okay, so with that out of the way, let's see the actual case studies. The first broad category of data loading scenarios that I'm going to show you are related to fetching relationship data. And so there are lots of ways to do that and some developers have their own preferred way of doing that. So let's see some of these techniques and what the advantages and disadvantages for each of them are. The first one is what I call lazy fetching which is the default behavior in Amber data. So if you have a relationship between bands and songs, a band has many songs, and then you have the following routes. In the band route, you of course, that's like the classic Amber route, Amber model hook. You just grab that one band which is designated by its ID. And then in the songs template where you still have the model is still the band, you say model.songs. So it's only in this moment when Amber renders that template that this relationship is going to be fetched. So let's see what that looks like in practice. You can see that if I click one of the bands to see their songs, then there is like a blank page with an empty list. And then when all of the songs are returned from the API from the backend, the list is of course rendered with the songs. So I think definitely the advantage is that it's very simple and it just works. And you never fetch data that you don't need. So you don't fetch the songs of a band which is not visited. On one downside though, is that you don't really control, you didn't really think about how this data is loaded. So you can totally trigger and request in this case. So if a band has 10 songs or 20 songs, then you might trigger 20 songs, like song slash one song slash two and so on. And there is also this disturbing flicker that is not ideal. So let's see whether we can do something about that. The models stay the same, but what we do now in the songs route is that not only we load the band, or just grab the band, but we also already load the related songs. And by virtue of having a promise returned, EmberRCP hash returns a promise, you make sure that you are blocking the rendering of the template. Until all of the data is in. So now if we check that again, you will see that indeed, you can even see the spinner, so data is loading, and then you see the full list. So there is no flicker. So the takeaway here is that if you want this blocking behavior, then one way to do that is you just move everything that you want to load before you render a template into the model hook. So that's, I think, definitely a better user experience. You still have that, the risk of triggering and requests, however. And also, I think it's a slide disadvantage, but RSVP hashes, by some it's considered like an anti-patterning in model hooks. So let's see another way of removing the flicker. And now we will leverage JSON API. So if we pull up the spec, it says an endpoint may also support an include request parameter to allow the client to customize which related resources should be returned. Okay, so we need to use the include parameter when you make a request to the backend. And number data has first class support for that. You can just pass the include option and then the name of the relationship. So that's what we are doing in the band route. So now I'm fetching the band, but we tell the API to send us also the related songs. This is what it looks like. The actual requests look like. And what the API returns is that under data you have the primary source, but you can see that you have also an included key and there you have the related resources. This is by the way called compound documents in the specification. So we might think that now we are done. We are removing the flicker. Again, if I click let Zeppelin, the songs are loaded, but actually the flicker is not removed. You can see, first you can see the empty list and only after that the full correct list is rendered. So why is that? You might have thought that by side loading the songs, we again blocked the rendering of the template by returning it as a promise, but it's not. Well, it turns out that if you remember the find record, we are returned immediately if that band is already in the store. And it is already because we have nested routes and we loaded all the bands for the list of bands on the left. So the fact that we pass in the include songs doesn't alter that behavior. So we need to tell Ember data to reload that record already, even if it's already in the store, and we do that by passing reload equals true to find record. And with that amendment, it's now working as we wanted to. So here we leverage JSON API, that's a positive thing. And I think another advantage is here, the US developer had to think about side loading things. So you have more explicit control over how you load that data. However, by passing that reload true option, we delay the rendering of the band template because if it didn't pass that, then it would have returned immediately. Now this is no longer the case. So in this application, this is not a biggie because we don't really render anything in the band template, but your user case might be different. And I also want to mention the references API, which is available in Ember data since version 2.5. It's another great way to check whether a relationship is loaded to load it or condition not loaded. So, and the takeaway from all of these scenarios that we saw for building relationships is that I think that data loading strategies should be as much a part of the design process as much as, for example, designing your UI. So it shouldn't be an afterthought or shouldn't just say that it works. Okay, let's leave relationships behind us and then focus on searching on the backend. So here the specification says that the filter query parameter is reserved for filtering data. Servers and clients should use this key for filtering operations. Okay, so since searching is a form of filtering data, we'll use that. So you can see that I modified the model hook for the song's route. Now if there is a search term that on line 13, I'm now doing a query for songs and I'm passing in the search term. I also wrap this in a filter key and Ember data does the writing. I mean it just serializes this to the right request that you can see at the bottom. There is one problem though, is that this does a global search. Led Zeppelin doesn't have a song or a daughter. That's how I knew that something was wrong. So we have to modify this code to restrain the search through those related to the current band. And I did this by passing in the band ID also. And then in the adapter, I'm composing the URL so that the URL is the relationship URL that is queried. So it's going to be something like band slash 24 slash songs and then the search term as a filter. And with this, it now works correctly. So really just the search is just for the band whose songs we are looking at. So if you want to do some searching, then use the filter parameter, sorry, the filter parameters in JSON API. Sorting is another prevalent thing in Ember applications and JSON API is something to say about these two. An endpoint may support requests to sort the primary data with the sort query parameter. The value for sort must represent sort fields. The sort order for each sort field must be ascending unless it's prefixed with a minus sign in which case it must be descending. Okay, so we have to use the sort query parameter to sort the data. So in the band's route, I didn't change the code. I'm going to tackle this in the adapter layer. In the songs route though, I'm passing in the sort because I want to be able to modify the sorting criteria by clicking on one of these buttons. And then in the template, I'm just switching the value of that sort by parameter that changes this. And so in the adapter layer, in the case of the bands, it's just a static value, so I can just pass in sort equals name. And then for songs, so in the song adapter, I'm adding sort equals sort to the URL. So that sort comes from the query call to the store. You can see that in the first case, I'm setting the value of the sort as minus rating slash sorry, comma title. So that field first sort them in ascending order, sorry, in descending order of their rating. And then if there is a tie, I use the title to break it up. And this works perfectly. They use the JSON API sort parameter and you don't even have to transform it. You can just use it directly in your templates and controllers and pass it as it is to the backend. Now pagination, again, we take a look at the spec. Server may choose to limit the number of resources returned in a response to a subset of the whole set available. JSON API is agnostic about the pagination strategy used by a server. The page query parameter can be used as a basis for any of these strategies. So we are going to use a page parameter where specified a meta member can be used to include non-standard meta information. The value of each meta member must be an object. So we are going to use the meta object to contain the information about how many records there are in the collection. So an example of this is that if the backend returns the songs, it can also include a meta object saying how many pages and records there are all together. And so my adapter is growing larger and larger, but now I can add the page parameter, page number and page size. Both of these are necessary. And then, in the same vein as before, I'm from the route, I'm passing in the page number. The page size is now just set to 10. And then it's really easy to assemble our own pagination links, because it's quite trivial to do has previous page and has next page and then just use these in the template to see whether the previous and the next page links need to be rendered. And I'm just passing in for query in the page number, of course, just decrease or increase the page number. Again, now I added a few more songs, so we can see that there are at least two pages and you can see if pagination works correctly. And it does, and I can even search in the same time. So the URLs are getting bigger and bigger, but we don't really care about that and we are doing lots of things. So sorting, searching, and pagination are all included now. So use just an API's page parameters and the pagination metadata. So that closes that section of the scenarios and I want to end with a scenario that intrigued me for quite a while. So we know that if you want to indicate to the user set that some data is being loaded from the back end and this is done in the foreground, so to speak, then it's relatively easy to do that with the loading substrate, the corresponding loading template or the loading event depending on your needs. But I think what is harder to do is to do the same thing when ember data is fetching data in the background. And I came across this, came across this problem some time ago, I wanted to solve it. So to able to demonstrate this, I added two more routes, the application called artists and artists. The important thing about these is that they are not nested. So it's possible to load just one artist to the store without loading all of them, which was not possible before with nested routes. There is nothing fancy going on in the routes though. I'm just fetching all of the artists in artist.js and I'm fetching the one artist which is specified in the URL in artist.js. And the template, again, nothing really special about that. The only thing is that I want to show a spinner when the is loading artists flag is true. So that's the flag that we should set correctly. So it looks like this, again, a list of artists on the left. And now if you click one of the artists, then the page is taken over by that page, the detailed information about a single artist. So the following scenario then becomes possible. You start on the detailed page and then you go back to the list of artists. And what you see is just one single artist, the one that we booted up the app on. And I think that's quite perplexing to the user. I mean, they can be terrified where all the artists have gone. So that's where I want to improve the user experience and show the spinner that data fetching is going on. So by the way, this is the case, again, because of the eager return behavior of find all. So if you remember, if find all finds at least one record already in the store, then it will return immediately. And that's what we can see here because that one artist is already loading. And it does then a background refetching of all of the records. So what I did is that in the model hook, I first see with peak all whether there are any artists in the store. So this will not trigger a request to the backend. And if there are none, then I can fetch them all via find all because I know that's going to block the model hook. And I can show them a smear to user. But if there is at least one, then I return all of them on line nine. And at the same time, I schedule fetching all the artists for later. And fetch more artists, what it does is that now I can set that load flag to true and I can then fetch all of the artists with find all passing in against reload true because we know that there's at least one artist. So you don't want an immediate return. And once that's back from the backend response, then we can set the model to this new value to the full list of artists. And I shouldn't, of course, forget to reset the loading flag to false. So let's see now. So we start with flee. And then once we go back to the artist, we now have this nice spinner. So the user is relieved. So what I did essentially is that I deconstructed the background data fetching process just to have more control and be able to set loading flags. And I wasn't quite satisfied with that. So that gave me an opportunity to do something with Ember concurrency that had been meaning to do for a while. And just maybe two sentences about Ember concurrency. It's a great add-on for managing asynchronous tasks. And you can do, you can really do some things that would be very, very complicated or outright impossible with promises. It does a lot more, but that's the important thing here. So now with Ember concurrency, what I did is that I now return a simple JavaScript object from the model hook. The reason I'm doing that is just to have it return immediately. And then I set, I defined a number concurrency task called fetch artist task. And so I'm initiating one instant of that task by calling perform on it. So after that, the setup controller will be executed. And then again, with a peak call, I'm checking if there are any artists. And I'm setting those artists already on the loaded artist. That's so I'm able to show to the user some artists already. And then I introduce like an artificial timeout in the fetch artist task, so line 20, just to be able to see the spinner. And then I can now do the find or call in that task. So now in the controller, what I'm doing is the artist's property is going to be the most important part here. I can check, and that's why I'm doing on line 10, whether that Ember concurrency task has already finished. If it has, then I can return its value. So its value is going to be whatever was returned from the fetch artist task in the upper left, which in this case is going to be the full list of artists. But if it's not finished yet, then I already have my loaded artists and I can just return this. And so that's what I'm iterating through in the template. Let's going to do the right thing. And another added bonus if we use Ember concurrency is that it has all of these status flags on the task. So I don't have to do that manual. So I can just use the task that is running to be able to know whether are we still fetching data. So I think that's a superior solution because there is, I didn't need to manually load the flags. Just manually set the flags. There was no run loop scheduling involved and I don't even have to pass the reload through option to find all. So one more thing. Before we wrap up is that I prepared a page on my site just for you. It contains the slides for this presentation but it also contains a pointer to a GitHub repository which includes all of these scenarios and then some more which I didn't have time to cover here. And on top of that there is also a mini book that I assembled from these examples. So if you'd like to learn more about this then check out that site. And thank you very much for your sustained attention.