Ember-data and json-api: why handle relationships client side?


#1

I’m finally getting into ember data and the json-api standard. I’d say I have a rudimentary understanding of them (stay tuned for just how rudimentary)…

I am having a hard time figuring out why you’d want to handle data relationships on the client side.

Let’s say I want to load a category, and that category has 112 products in it. I understand how the ‘category’ and ‘products’ models are set up, but when this is loaded, it’s going to trigger 113 xhr’s. OK, I can limit it to 16 or 32 per page, but still we’re talking about alot of xhr’s. Then you add in any assets (like images) that each rendered product needs, you double the number of http requests. I guess I don’t really see the advantage of that method, over the “traditional” method of having the server put everything together in a single payload. Unless…I am completely misunderstanding something!

Also, let’s say you need to do some complex sorting like “these 8 items need to always appear first for category x”, or “make any backordered items appear further down in the results”. Or even, heck, “sort by price”. With my traditional SQL approach, I’d build as much of this logic right into my queries as possible, to reduce the amount of application code. Then you can run the same query again with LIMIT and voila, you can page thru a highly customized dataset.

How would that work with ember-data and the simple relationships? I am guessing you’d need to load in the entire result set (112 xhr’s?) and THEN run it through the sort function, and some kind of pagination function.

I’m SURE solutions exist to these questions (or explanations that dispel my naive ideas!), but I am having a hard time digging them up. The tutorials I’ve found are great, but are simplistic intros (as they should be). I am pretty sure ember-data is a great tool, but having a hard time getting my head around it! I think I’m actually at a disadvantage here because of years of “traditional” web development. Any help appreciated!


#2

There is DS.Adapter#findMany to help you combine those requests.

You can absolutely do that. Just use ajax.request to get whatever you need then push it into the store with Store#push


#3

Cool - thanks lightblade. I think not using the JSONAPI stuff starting out is probably a good idea. Until I can get a better grasp of it.


#4

I think you’re missing this bit of info from the JSON API spec http://jsonapi.org/format/#fetching-includes

If, for example, you are requesting 10 articles that each have a comments relationship, you can tell you server to return the articles and all it’s comments in one XHR request.

https://guides.emberjs.com/v2.12.0/models/relationships/#toc_retrieving-related-records

this.store.findRecord('article', id, {include: 'comments,comments.author'});


#5

ahhhh…I figured there was a way to do it! I certainly do like the idea of a standardized JSON specification. Makes a ton of sense. I know it’s in the early stages of development, hoping the docs and examples get fleshed out a little more (like the ember docs are). it’s hard to learn from what’s there, it reads like a legal document! I’d love to see more working examples of actual JSON-API documents. And a linter! :smiley:

Though I do like the little easter-egg “I like XML better”. Hahahahaha!


#6

Hi again!

As others have alluded to, I think you’ll find that Ember Data has your typical “entity” relationships figured out. You can consolidate your requests into one query as they’ve mentioned with the findMany. You can “side load” relationships so that you can cut down on those requests, too. Also, let’s say there’s a relationship but it isn’t needed right away. With an async: true relationship to another model you can have them retrieved lazily where you get a promise but only when you get and ask for that relationship.

There’s the caching layers, too. You can peek to see if its in the store, and take different actions as needed. The EmberConf 2017 talk that just happened actually had some really great strategies for Ember Data. This is the talk: http://emberconf.com/schedule.html#data-loading-patterns-with-json-api

It was really awesome to see different strategies to even some of the finer oddities with patterns, keep your eyes open for when this video gets posted.

The majority of these wins you basically get for free when you use the JSON API standard as lightblade mentioned. Of course you can write your adapters and serializers yourself, extend the existing ones to do one-off cases. Ember Data is incredibly powerful.


#7

The other part you’re missing here is the links property which means you don’t have to include all the data about the relationship in your request.

Of all the approaches mentioned above, the most common and sensible one for hasMany relationships in ember is to use the links attributes, not to serialize the list of ids in the relationship and use findMany, or manually push json in the store.

For belongsTo relationships, just serializing the id is the usual approach, ember-data will know how to load a single record by id just fine.

(Of course, you can use the include param to include more records if you know you need them all loaded up front, but often you don’t want to load everything all at once because it’s going to be a lot more data to load)

I think not using the JSONAPI stuff starting out is probably a good idea. Until I can get a better grasp of it.

I would not recommend this at all - you will likely find it a lot harder than using json-api with ember data.


#8

OK, that’s helpful. Thanks. I’m trying to think how my common use cases would be set up both with JSON-API and ember-data. I think I have the relationships figured out. But I’m curious to know how you guys might approach my second example in the OP…

A category with 112 products in it that needs to be sorted (to make it simple, by price), and paginated. With my frail grasp of ember, seems like there are 2 options:

  1. load all 112 items into the store, sort the model by price and then set up some kind of pagination in the application

  2. configure the adapter to send sort= and offset= and pagesize= parameters to the back end where the query, sort and chunking of the data set takes place.

#1 seems a bit heavy, and #2 requires you to split the logic between client and server. I’m not against either approach, but I’m just wondering what the “ember” approach to this might be.


#9

112 is small enough to be borderline if it’s worth paginating server side or not. It’s fine to handle that on the client or the server. You can do it with computed properties on the client side.

For server side pagination, persionally I would use store.query along with filter / sort params to get a page at a time from the api. Often this combines nicely with client side ember queryParams, and using refreshModel option so that the model hook refreshes when the query params change.

So you’d do:

queryParams: ['page', 'sortOrder'], in the controller, then set refreshModel to true in the route for those query params, then just use store.query in the model hook to load the right page


#10

OK -makes sense. Thanks for taking the time to answer!