I've tried Backbone relational before and hadn't had a great experience with it. Although that was a long time ago, and it may be robust enough to make sense now. Regardless, personally I'm not even sure built in relations have a place as a Backbone library (I even remember a talk by jashkenas where he briefly mentions not supporting relations/nested models in Backbone because Backbone core peeps though it was a bad idea). My experience tends to agree because API conventions can vary quite a-lot, even just in our own API. There tend to be more edge cases to handle than makes it worth saving a couple lines of code here an there.
I had attempted to write my own relational library for Backbone back in the day. But ultimately decided to drop it because of this exact point, it felt like a leaky abstraction. Instead I opted for a light-weight mixin for relations that Torque/Inertia uses. Although that has mostly been successful, I'm still not convinced it's a good idea because edge cases would just pop up all the time.
An example of how one would handle our relational API data in Backbone without a third party library could be to simply wrap them in functions like .artist() so that we can handle the edge cases per model.
class Artwork
artist: ->
@_artist ?= new Artist @get 'artist'
class Partner
shows: ->
shows = new PartnerShows
shows.url = "/api/v1/partner/#{@get 'id}/shows"
showsOn the server where you have control over how your data is saved and returned I think relations make a ton of sense (especially (obviously) when backed by relational databases). I'm just not convinced someone out there is going to be able to write a library that successfully abstracts relations for all the different RESTful APIs out there.
Given my skepticism, if we decide to adopt one of the 3rd party libraries I would suggest a light-weight one like Backbone Nested Attributes, but would be really curious to see how Backbone Relations works for us now.
Repositories essentially try to solve two problems (last time I checked):
- An identity map that passes around the same models across the app
- Client-side caching
There's one third party solution to identity maps I've found here. But as jashkenas points out in a reply it's probably an over-engineered solution when you consider collections have all the identity-map-like behavior you need. Instead of adding extra infrastructure and concepts, a simpler solution would be to have a top level collection like App.Artworks and simply use "get or add" functionality.
e.g.
getOrAdd: (artwork) ->
artwork = @get(id) || @add(a = new @constructor id); a Backbone 1.0 even added Collection::set which does a lot of the logic the Repository aims at when dealing with smart updates to a collection. A top-level collection should also be clear when it comes to questions of where you can store new models you want to share across the app, and if those models have already been populated with data or need to be fetched.
e.g.
Although a deprecated example, let's say you need to add an artwork to your favorite's tray in the footer when you click favorite on a list item.
# In ArtworkListItemView
@artwork = App.Artworks.getOrAdd(id)
save: ->
@artwork.trigger 'favorite'
# In FavoritesView
@favorites = new Artworks
@favorites.url = '/api/v1/me/favorites'
@favorites.fetch().then (artworks) ->
# It might need some options, but `set` should smart merge these things
# so that @favorites and App.Artworks are using the same model instances.
App.Artworks.set(artworks)
@favorites.on 'favorite', @renderAs for client-side caching, I think it's a dark hole to go down. But this pattern should provide simple solutions to being able to avoid re-fetching an already fetched model. If anything more advanced is necessary it's time to write garner for local storage.