|
GET and POST dataGET data is data attached to an http request via the url string. In the job board app, an example of this is tphyahoo's profile, where the user is specified on the url string. Another example is fetching a particular job. POST data is data attached to a request after submitting a form. One place this is used is in the registration process. Once you have a user created, you can also see POST in action by editing your profile or creating jobs. Happstack deals with GET and POST data similarly. Let's look at how tphyahoo's profile gets displayed. Controller.hs: ... , dir "viewprofile" [ methodSP GET $ userProfile rglobs ] ... using dir and methodSP as above is a common pattern. dir pops the head element of the path array ["viewprofile"], resulting in an empty array. methodSP checks that the path array is empty and that the method is GET. If so, control is passed to the next sp: userProfile rglobs, which is in another module. Now once we can select for any HTTP method, how do we actually grab data from the request? Fundamentally, this comes down to the FromData class. Again, we can fire up ghci and check it out. ghci>:i FromData
As you can see, there are a few convenience instances defined for tuples of FromData instances and for the lift of a FromData instance into Maybe. How does one actually make an instance of FromData yourself, though? The basic way is to use look. ghci>:t look
Another note is that RqData is an instance of Monad and MonadPlus. Between these instances and look you should be able to easily define your own instances of FromData. We'll be looking at an example from the code running this tutorial below. data UserNameUrlString = UserNameUrlString {profilename :: String}
Since we have an instance of FromData defined, we can use it with a code fragment like the following.
ghci> :t getData
There's also another function you can use which is helpful when you don't actually
need do notation and just want a one line function.
The above is the main pattern for processing GET or POST data in Happstack. Please look through ControllerGetActions.hs to get more examples of using this. To summarize, you decide what argument type withData should accept. This might be a datatype you have already defined, like User or Job (which already plays a major role in the app), or it could be an ad-hoc datatype which is only used this once in the form processing. Whatever the case, you declare that data type an instance of FromData, and define how it should grab data attached to the request. In this case, UserNameUrlString takes one argument, so we use liftM -- for two args we would use liftM2, three args liftM3 etc. To get that one arg, we look for a request GET variable named "user" and if we don't find it we use a reasonable default, in this case the empty string. The result is a value of type UserNameUrlString which gets passed to the ServerPartT handler in the userProfile function. Next we cover uploading files |