0

Visualize a bytestring body on a webserver run on Spock (localhost for instance)

My goal : create website and view a bytestring (converted to text) Framework: Http Simple for performing request to restAPI Spock for my server I don't want for instance to create a JSON as I need to manipulate/inspect my response before creating a JSON structure. General idea is that I want to use the response body to construct a JSON query structure (the user will be able to compose his question) that will be sent to the restAPI website.

I manage to build a request like this:

    connect = do
        request' <- (parseRequest "http://localhost")
        let request = setRequestMethod "POST"
                    $ setRequestHost (S8.pack ("xx.xxx.xxx.xxx"))
                    $ setRequestPath "/api/Integration/Login"
                    $ setRequestBodyJSON me
                    $ setRequestPort 1000
                    $ request'
        response <- httpJSON request
        return (getResponseBody response :: Auth)

then I used it to query the API page

getRequest :: RequestPath -> HtmlT IO L.ByteString
getRequest rpath = do
        atoken <- liftIO connect
        request' <-  liftIO (parseRequest "http://localhost")
        let request = setRequestMethod "POST"
                    $ setRequestHost (S8.pack ("xx.xxx.xxx.xxx"))
                    $ setRequestPort 1000
                    $ setRequestPath (S8.pack ("/api/Integration/" ++ rpath))
                    $ addRequestHeader hAuthorization (S8.pack (unpack (token_type (atoken)) ++ " " ++ unpack (access_token (atoken))))
                    $ setRequestBodyJSON r1
                    $ request'
        response <- httpLBS request
        return (getResponseBody (response))

then I follow with a short SpockM monad:

app1 = do get root $ text "root"
          fct 

with fct equal to

fct = do get "/further" $ lucidIO ( fmap TL.decodeUtf8 (getRequest "GetProperties"))

Everything compile fine I am even able to see the result in GHCI with invocation like : connect >>= (\ x -> print x) (same with getRequest "GetProperties" ) What I don't understand is that lucidIO should give me a ActionCtxtT ctx m b type, which perfectly fit the type of a handler (for example like the text function in the do get ... $ text -> ActionCtxT ctx m a) and should be processed by the spock function in main() ie runSpock 8080 (spock spockCfg app1) I tried to get rid of the ByteString 'ending' type replacing it with a () in order to mimic as close as possible the Html () type which shows up and work in lot of examples I studied. All parsing and request building is done with the HTTP.Simple (it's not very elegant I know for instance it just have to work) which pulls me from start in a monad (due to the first function 'parseRequest' -> m Request) from which I cannot escape until lucidIO - may be I am choosing the wrong Monad (ie IO : but with IO I am able to check everything in ghci). Could you give me some hints on how to get this ByteString printed in my browser?

sjakobi
  • 3,546
  • 1
  • 25
  • 43
user3680029
  • 179
  • 8

1 Answers1

0

So finally I achieve what I was looking for - woua I am really proud of me ... Okay for those who will look for the same thing, what I've manage to do, to recap my main problem was to escape the IO monad (my choice may be not clever but still) in which I was stuck due to the use of request parsers from HTTP.simple library. My code change a little bit but the general idea stays the same:

building a Response query:

getResponseMethod  :: RequestPath -> RequestBody -> IO (Maybe Value) 

from which thanks to the decode function (aeson package) a Maybe Value is obtained (wrapped in IO but that's okay)

then my little spock server:

main :: IO ()
main = do
    spockCfg <- defaultSpockCfg () PCNoDatabase ()
    runSpock 8080 (spock spockCfg app)

I work a lot to have the right app -> SpockM () () () () I started with the simplest app we could imagine:

app = do get root $ text "Hello!"

noticing that the text function is producing a MonadIO m => ActionCtxT cxt m a monad so my thought was that if I 'sprinkle' some clever LiftIO thing it should do the job.

I create a helper function:

extrct :: MonadIO m => ActionCtxT ctx m Text 
extrct = liftIO $ do
     a <-  getResponseMethod "GetProperties" r1
     return (pack $ show a)

and with a twist of hand adjust my app

app :: SpockM () () () ()
app = do get root $ do
            a <- extrct
            text a

and finally I was able to see the string representation of the Maybe Value :: JSON on my spock local webserver. That's what I was looking for. Now I can work on cleaning my code. From what I understand using liftIO will place the IO monad in the rigth place in the Monad Stack that's because IO is always at the bottom?

user3680029
  • 179
  • 8