Hi all,
I'm developing a small web app using Snap with snaplet-auth and
snaplet-sqlite-simple [1].
While using some of the Snap.Snaplet.Auth helper functions, I came up
with a couple of suggestions.
1. Helper function requireUser should call the "good" handler with an AuthUser
requireUser :: Lens b (Snaplet (AuthManager b))
-> Handler b v a -- bad (not logged in)
-> Handler b v a -- good (logged in)
-> Handler b v a
Wouldn't this make more sense as:
requireUser :: Lens b (Snaplet (AuthManager b))
-> Handler b v a -- bad (not logged in)
-> (AuthUser -> Handler b v a) -- good (logged in), call
with currently authenticated user
-> Handler b v a
This way the handlers that require the user to be logged in wouldn't
need to separately get the currentUser and match it for "Just user".
The currentUser returns a Maybe AuthUser so every handler that needs
to access the AuthUser will need to deal with this Maybe value, even
though they probably were called by requireUser which already ensures
that the user is logged in.
I would argue that any application that has multi-user support with a
database backend will need access to AuthUser in the majority of its
handlers.
2. Why is AuthUser userId a Maybe UserId instead of UserId?
Why would the AuthUser userId field ever be Nothing? I realize there
may be a need for not specifying the uid for a user when creating new
users in the db, but will this field ever be Nothing once a user has
been persisted to a database?
I'd like to pass in AuthUser to my handlers that need to query data
based on the currently logged in user. But because userId is "Maybe
UserId" instead of just "UserId", every handler needs to deal with the
possible Nothing value. I worked around this by adding my own User
type which doesn't use Maybe for the user id. (I realize many bigger
apps will have their own User type anyway.)
Here's how my code for requiring a logged in user looks like:
-- Run actions with a logged in user or do nothing (error)
withUser :: (User -> Handler App App ()) -> Handler App App ()
withUser action = do
with auth currentUser >>= go
where
go Nothing = return ()
go (Just u) =
maybe
(return ())
(\uid -> action (User (read . T.unpack $ unUid uid) (userLogin
u))) (userId u)
Is there a reason for this use of Maybe that I'm missing?
Thanks,
Janne
- [1]
http://hackage.haskell.org/package/snaplet-sqlite-simple