I try to be as RESTful as possible in building applications but one thing that I'm never sure about is how to create a wizard-type work flow, be RESTful and concise.
Take, for example, a multi-page sign-up process.
Option 1: I can create a controller for each step and call new or edit when user gets to that step (or back to it). I end with step1_controller, step2_controller, etc...
Option 2: I can create a one controller and track where they are in the sign-up process with a param, session variable, state-machine - whatever. So I'd have signup_controller/step?id=1
The first option is strictly REST, but not very concise and ends with some number of extra controllers. The second options is more concise, but breaks REST, which I'm willing to do, but I don't take it lightly.
Is there a better option?
I'm working in ruby on rails, but this question applies to other MVC implementations, like ASP.NET MVC
I'm actually less concerned about maintaining REST in a one-shot wizard. REST is most important, I think, with repeatable actions -- you want the url to be basically bookmarkable so that you get back the same view of the data regardless of when you go there. In a multi-step wizard you have dependencies that are going to break this perspective of REST anyway. My feeling is to have a single controller with potentially separate actions or using query parameters to indicate what step you are on. This is how I've structured my activation wizards (which require multiple steps) anyway.
Although the answers are very nice options indeed I still use the approach given in:
Shoulders of Giants | A RESTful Wizard Using ASP.Net MVC.
It is definitely worth a look. Though I must say, the answers given here make me think to remake this wizard when I have the time.
If you apply some DDD logic here, which compliments the "M" in MVC, the state of the UI (registration progress) belongs in the Application Layer, which can talk directly with the Domain and Infrastructure layers (Four layers: UI, Application, Domain, and Infrastructure). The concept of DDD makes you "think" about how to solve the solution in code first. Let's step through this...
It's the Progress Bar
The state you want to maintain here is the step or progress of the registration. So, my first step would be to document progress or "steps". Such as, Step 1: Get Username/Pass, Step 2: Get Email. In this case, I would apply logic to "move" the Model to the next step. Most likely with a NextStep() method on the a RegistrationService (RegistrationService.NextStep()).
Ah, but it belongs in the App layer
I would create a service in the Application layer called RegistrationService. I would place a method on here called NextStep(). But remember, the Domain would not hold the state of the model here. In this case, you'd want to focus the state at the Application layer. So in this case, NextStep() would act upon not a model object (since it is not part of the Domain responsibility), but instead the UI. So, you need something to retain the state of the Registration process.
Get away from the Domain Model, how about a ViewModel?
So now we know we have to retain the state of something in the UI. MVC allows for a concept called ViewModels (in ASP.NET MVC, not sure what RoR calls it). A ViewModel represents the model that will be displayed by the view, and/or partial views.
The ViewModel would be an excellent place to save the state of this object. Let's call it, RegistrationProgressViewModel() and stick a NextStep() method on it. This, of course, means that the Application layer would have to retain the location of the RegistrationProgressViewModel, and the APplication layer would change the internals of it based on NextStep actions. if it is complex, you may want to create a RegistrationProgressService() in the application layer and place the NextStep() within it to abstract your logic away.
How to pass the ViewModel around?
The final piece is how to track the state of that object. Since web applications are stateless, you have to retain control by some other means then the application. In this case, I would revert to either: 1) Serializing the ViewModel to the client and letting the client pass it back and forth, or 2) Keep a server-side copy of the ViewModel, and pass some type of identifier back and forth to the client and back.
This is a good example to think about, as I have not performed this myself yet. For #2, the most secure and insured way of saving the state of this ViewModel is to persist it to the via the Infrastructure layer (yes, the APp layer can talk directly to the Infrastructure layer). That seems a lot of work to me, for something that may die off and I would have partial registrations sitting in my DB.
But, #2 would keep the user's private info (username, password, email, CC #, etc) all on the server side and not pass it back and forth.
Finally, an answer!
So, after walking through it, we came up with:
This way, you never have to track what "step?id=2" on the View or UI itself, as the ViewModel gets updated and updated (Authenticated, Verified, persisted to DB) as you move forward.
So, your next concern would be to "move forward" in the UI. This is easily done with 1 controller, using step or named steps.
I apologize, but I am writing C# code below as that is my language.
You'll notice that this abstracts the "Business Logic" of verifying the model's internal state into the RegistrationProcessService.NextStep() method.
Good exercise. :)
In the end, your "RESTful" url is a nice and clean POST to: /register, which expects a ViewModel with specific properties filled out. If the ViewModel is not valid, /register does not advance to the next step.