Haskell database query inside ScottyM() function

315 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 best solutions below

0
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.