I am new to haskell and have honestly hard times with it. But it expands my thinking, so here we go. I am trying to run a really simple Webserver that queries a Postgres DB and should return the result as JSON.
The query is absolutely simple: "Select id,data from MYTABLE where id = 1"
But the type system of haskell is killing me right now and the final type of my actions doesn't match up. I am using Spock and PostgreSQL-Simple as a Combo.
Most tutorials are either to simple for what I want to do or to difficult. I am somewhere inbetween and miss a lot of Haskell understanding, a lot of my previous problems I have already solved by simple copy and pasting and got a simple version working.
But as soon as I try to pass on a route variable I am failing.
Here is my working version. My Database Table is here called "Envelope", The important call is where it says get "json"
:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
module Main where
import Web.Spock
import Web.Spock.Config
import Database.PostgreSQL.Simple
import Data.Pool
import Data.Aeson (ToJSON(toJSON), object, (.=),Value)
import Database.PostgreSQL.Simple.FromRow
type AppAction a = SpockActionCtx () Connection AppSession AppState a
data AppState = EmptyState
data AppSession = EmptySession
data Envelope = Envelope { envId :: Int, envData :: Value } deriving Show
instance FromRow Envelope where
fromRow = Envelope <$> field <*> field
instance ToJSON Envelope where
toJSON (Envelope envA envB) = object [ "id" .= envA, "data" .= envB ]
main :: IO ()
main =
do pool<-createPool (connect (ConnectInfo "localhost" 5432 "" "" "envelopes") ) close 1 10 10
spockCfg <- defaultSpockCfg EmptySession (PCPool pool) EmptyState
runSpock 8080 (spock spockCfg app)
app :: SpockM Connection AppSession AppState ()
app = do
get root $
text "Hello World!"
get "json" $ do
xs<-runQuery $ \conn ->
query_ conn "select id,data from envelope where id = 1"
json (xs::[Envelope])
Then I try to pass on the Envelope ID with a lambda function, for that i also need to change PostgreSQL-Simple query_
to query
:
get ( "json" <//> var ) $ \eid -> do
xs<-runQuery $ \conn ->
query conn "select id,data from envelope where id = ?" (eid :: Int)
json (xs::[Envelope])
The error I get says:
No instance for (ToRow Int) arising from a use of ‘query’
In the expression:
query conn "select id,data from envelope where id = ?" (eid :: Int)
In the second argument of ‘($)’, namely
‘\ conn
-> query
conn "select id,data from envelope where id = ?" (eid :: Int)’
In a stmt of a 'do' block:
xs <- runQuery
$ \ conn
-> query
conn "select id,data from envelope where id = ?" (eid :: Int)
I also have problem to return just the first item from the query, even without the lambda function.
Full Source can be found on bitbucket
I hope someone has the time to help me out here. Thanks for reading already.