简体   繁体   中英

How to fetch on /users/profile and /users/friends with BackboneJS

I have an API with many urls like:

/users/profile -> GET the currently connected user 
 /users/bestfriend -> GET the currently connected users' best friend (most bestfriend of bestfriends)
 /users/wife -> GET the currently connected users' wife


 /users/friends -> GET the currently connected users' friends
 /users/bestfriends -> GET the currently connected users' best friends
 /users/childrens -> GET the currently connected users' childrens
 /users/neighbours -> GET the currently connected users' neighbours

I'm new to Backbone and i don't really know if the currently connected user should be fetched as a collection or a simple model for exemple.

I know the current user could be boostrapped like the Backbone doc mention but it's not the point here, just assume i can't boostrap the current user model.


So how can i redirect my fetches to the API URLs? Should i provide each time an option like {"operation":"profile"} or {"operation":"friends"} , or modify the collection url before doing the fetch?

Thanks

Use the model.urlRoot property to specify the URL of the model if you wish to use the model 'outside' of a collection. It'll automatically append an id to the end of the URL if it's a new model (ie id==null ) and send a POST on creation. Else it'll fetch (GET) at the specified url.

If you don't want to have an id appended at the end: Just overwrite model.url to generate the actual endpoint URL that you want to fetch/put/post to.

Collections also have a property called url - if the url or urlRoot of the model isn't specified the collection's url is picked up as the root (if that model is part of that collection).

So you could just do either of these:

model.urlRoot = '/users/profile'; //appends id on put/delete requests
model.url = '/users/profile'; //direct endpoint. Can also be a function
collection.url = '/users/friends'; //fetch endpoint for collection. Could also be used by models to put to with appended id.

The Backbone's doc is quite comprehensive and self explanatory. I suggest you read these parts for example Model.urlRoot

UPDATE : As per your new URLs

I think the confusion is because of the way URLs are designed. It's not good practice to have end-points as plural/singular:

Ex: /user/friends - fine get all friends of user. But which user? Better still: /users/{id}/friends - get friends of a specific user.

GET specific friend for user: /users/{id}/friends/{id}

I suggest adding ids to your URLs to make the most of backbone's built in REST-able functionality. Else, just define your own properties and logic and have separate function like 'save' to fire $.ajax calls yourself and do something on success/error callbacks.

Whether they are models or collections will totally be up to you. Fortunately/unfortunately there is more than one way to do it in Backbone. If you follow BB's way it'll offer a cleaner way of doing things since the framework expects and follows certain conventions. If not, you can always custom create. I've done both ways. Custom creating seems easier, following convention takes some planning but keeps it much cleaner albeit hides/abstracts away stuff from the programmer 'under the hood' whereas explicit ajax calls make it explicit.

It's a tradeoff. I suggest restructure your endpoints and use the url properties accordingly. Else just do what makes sense to you and your team and stick with it.

You have to create several Models and Collections any of them related to one of your URLS.

var Profile = Backbone.Model.extend({
  url: "/users/profile"
});

var BestFriend = Backbone.Model.extend({
  url: "/users/bestfriend"
});

// ...

var Friend = Backbone.Model.extend({});

var Friends = Backbone.Collection.extend({
  model: Friend,
  url: "/users/friends"
});

You also can use Friend as the parent class of BestFriend :

var BestFriend = Friend.extend({
  url: "/users/bestfriend"
});

Or even create a Person class as parent for every person :

var Person = Backbone.Model.extend({});

var Friends = Backbone.Collection.extend({
  model: Person,
  url: "/users/friends"
});

var Profile = Person.extend({
  url: "/users/profile"
});

var BestFriend = Person.extend({
  url: "/users/bestfriend"
});

As you have separate URLS to retrieve the data of everyone of the elements you should make several fetches:

var profile = new Profile();
var bestFriend = new BestFriend();
var friends = new Friends();

profile.fetch();
bestfriend.fetch();
friends.fetch();

You can reference all the elements into your Profile instance with things like this:

var Profile = Person.extend({
  url: "/users/profile",
  initialize: function( opts ){
    this.bestFriend = opt.bestfriend;
    // ...
  }
});

var bestFriend = new BestFriend();
var friends = new Friends();

var profile = new Profile({
  bestfriend: bestfriend
});

There are several approaches to organize the elements, also to listen to events on them, but all this is just a matter of taste, and which architecture you fill more comfortable with.

Essentially I agree with the first answer, but to keep it simple, you could start to use ids for the users and fetch them individually. This might create a bit of extra load, but it should keep the code cleaner until you need to optimize.

You might run into problems with the current API design. What if in the future you want the best friend of the wife? You will have an object which has the url "/user/wife" and you would then say "/user/wife/bestfriend". Next someone wants to expand this and have "/user/wife/bestfriend/children/". This would be rather complex to parse on the backend.

Essentially, instead of making separate calls for wives and children, have the profile call return the ids of the associated users:

/profile
{
  id: 165735,
  name: "Peter",
  age: 45,
  wifeId: 246247,
  childrenIds: [352356, 134098]
}

Then fetching the wife would simply be:

/users/246247

This would make the wife stay a real User and not just someone's wife. You can check the security here when retrieving a user, since you anyway have the relationships stored in the database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM