tags:

views:

126

answers:

3

I'm building a little tool to help people decide on group activities, like what restaurant they should go to for lunch. My objects are events, options and preferences. An event has several options, a user can rank the options on an invent in order. So a user's votes may be 1:option B, 2:option A, 3:option C.

My question is what is the best way to map this to REST? It seems clear that I should support CRUD on events, with

GET /events/ : list of events
POST /events/ : create a new event
GET /events/1 : get event one
and on options with:
POST /events/1/options : add a new option to the event

(in all cases, there must be an authenticated user)

Where I get confused is how does a user vote on the options for the event. What seems to fit REST best is to do a PUT for each option, to /events/1/options/1/vote, but this seems like it would be hard to enforce requirements between the votes, for example, if I wanted to force the votes to rank the options without ties, I could do this if I got all the votes at once, as in 1 B, 2 A, 3 C, but if the user changes his votes to 1 C, 2 B, 3 A, the app would be in an invalid state between those requests.

Should I make the votes a single package, and access them at /events/1/votes?

(This may seem an excessive amount of planning for a weekend project, but my purpose is to do it right, since I don't have that luxury on code I'm paid to write.)

A: 

I would do it this way:

/events/1/options/vote/1stchoice
/events/1/options/vote/2ndchoice
/events/1/options/vote/3rdchoice
/events/1/options/vote/4thchoice
…

That way, if the user wants to vote for A as his first choice, B as his second choice, etc., he would PUT "A" to /events/1/options/vote/1stchoice, "B" to /events/1/options/vote/2ndchoice, etc.

If the user wanted to change his choices (say, make B first, A second), he would need to DELETE his votes and then recast.

In polls where users can only select one option, only options/vote/1stchoice would be enabled.

tetromino
The URIs don't matter - the important thing is that these URIs are sent in a response to some entry point, as fields, so that the client doesn't have to construct them or know anything about their contents.
Wahnfrieden
+3  A: 

Since votes are records that relate a user, a vote, and an option, I would design the voting as POST to /votes, essentially as a create action for these voting records. Then you can obviously combine several votes into a request that looks something like the following example (in json):

POST /votes
[
    { option: 38, vote: 2 },
    { option: 39, vote: 1 },
    { option: 40, vote: 0 }
]

On the server you fill in the user and return an appropriate status code after your consistency checks.

Josef
A: 

I think the first thing you need to do is work out what the objects are that you are representing in you interface. This is the real first principle of designing a rest interface.

It's not clear whether your objects are the /event/options where the events own a set of options and the operation is 'add votes' or the model is a /person/preferences/option where the person's preferences are a set options and the operation is the same 'add votes'.

In either case the the idea previously suggested of POSTing a set of options all at once is a correct RESTFUL approach, where the /person/preferences or the /event are both own collections of options and when dealing with a collection, POST is appropriate.

If you were having users voting on individual options then in both cases you'd be setting the vote count for a particular option. In this case a PUT on /event/option/1 or /person/preference/1 (for option 1) would be appropriate

jottos