Haskell database query inside ScottyM() function

306 views Asked by At

I'm trying to write simple rest API. I use Database.SQLite.Simple, Scotty and Aeson. I have a problem with DB query inside ScottyM() route function. When I have something like this

routes :: [User] -> ScottyM ()
routes allUsers = do
    get "/users/:id" $ do
        id <- param "id"
        json ([x | x <- allUsers, userId x == id] !! 0)

main = do
    conn <- open "data.db"
    users <- ( query_ conn "select id, first_name, second_name, team from users" :: IO [User] )
    scotty 3000 (routes users)

everything works fine, but in this scenario allUsers will get updated only once at server start. I want to query every time anyone ask about it. So I wrote this:

routes :: Connection -> ScottyM ()
routes conn= do
   get "/users/:id" $ do
        id <- param "id"
        users <- ( query_ conn "select id, first_name, second_name, team from users" :: IO [User] )
        json (users !! id)

main = do
    conn <- open "data.db"
    scotty 3000 (routes conn)

I get error

Couldn't match expected type ‘Web.Scotty.Internal.Types.ActionT
                                Text IO [a0]’
            with actual type ‘IO [User]’
In a stmt of a 'do' block:
  users <- (query_
              conn "select id, first_name, second_name, team from users" ::
              IO [User])
In the second argument of ‘($)’, namely
  ‘do { id <- param "id";
        users <- (query_
                    conn "select id, first_name, second_name, team from users" ::
                    IO [User]);
        json (users !! id) }’
In a stmt of a 'do' block:
  get "/users/:id"
  $ do { id <- param "id";
         users <- (query_
                     conn "select id, first_name, second_name, team from users" ::
                     IO [User]);
         json (users !! id) }

how to fix that? Also how can I pass arguments to sql query if I want for example select * from users where id = id from parameters?

1

There are 1 answers

0
Shaun the Sheep On BEST ANSWER

The get function's second argument is of type ActionM. If you investigate further, you'll see this is just shorthand for the more complicated looking ActionT, with e as Text and m as IO.

Because your do block is of this type, you can't call IO functions directly. You need to use liftIO to get the right type. So just adding a liftIO before the query_ call should fix it.

There's an example called using scotty with IO in the project wiki which shows this.