Reputation: 185
I am following this tutorial which uses scotty with persistent to create a simple API .
However, I am trying to create a simple api with scotty and mysql simple library.
Now I am stuck at one point in code .
In the below code I am not able to convert getUser function to type "ActionT Error ConfigM" because of which my code is failing.
Can anyone help me with understanding how I can convert getUser function to achieve needed type signature?
Code
type Error = Text
type Action = ActionT Error ConfigM ()
config :: Config
config = Config
{ environment = Development
,db1Conn = connect connectionInfo
}
main :: IO ()
main = do
runApplication config
runApplication :: Config -> IO ()
runApplication c = do
o <- getOptions (environment c)
let r m = runReaderT (runConfigM m) c
scottyOptsT o r application
application :: ScottyT Error ConfigM ()
application = do
e <- lift (asks environment)
get "/user" getTasksA
getTasksA :: Action
getTasksA = do
u <- getUser
json u
getUser :: IO User
getUser = do
e <- asks environment
conn <- db1Conn config
[user]<- query_ conn "select login as userId, email as userEmail from member limit 1"
return user
Error
• Couldn't match type ‘IO’ with ‘ActionT Error ConfigM’
Expected type: ActionT Error ConfigM User
Actual type: IO User
• In a stmt of a 'do' block: u <- getUser
In the expression:
do { u <- getUser;
json u }
In an equation for ‘getTasksA’:
getTasksA
= do { u <- getUser;
json u }
Upvotes: 1
Views: 323
Reputation: 15949
You left out plenty of code (imports and pragmas and the definitions of User
, please include that next time - see MCVE.
But now to your question:
I would change the Action
type to the following
type Action a = ActionT Error ConfigM a
then getTasksA
has the following type signature
getTasksA :: Action ()
getTasksA = do
u <- getUser
json u
(alternatively you can write this as getTasksA = getUser >>= json
)
and getUser
getUser :: Action User
getUser = do
e <- asks environment
conn <- db1Conn config
[user] <- liftIO $ query_ conn "select login as userId, ..."
return user
[user] <- liftIO $ query ..
is a bad idea - if no user is found this crashes your application - try to write total functions and pattern matches. Better return a Maybe User
.
getUser :: Action (Maybe User)
getUser = do
e <- asks environment
conn <- db1Conn config
fmap listToMaybe . liftIO $ query_ conn "select login as userId, ..."
if you can wrap your head around it, rather use persistent
than writing your SQL queries by hand - this is quite error prone, especially when refactoring, just imagine renaming userId
to userID
.
you ask
several times for the environment
but then don't use it. Compile with -Wall
or even -Werror
to get a warning or even elevate warnings to compile errors (which is a good idea for production settings.
Upvotes: 2