retrieving the values from responseCookieJar - haskell

Here is how I am sending a get request:
import Network.HTTP.Conduit
import Control.Applicative ((<$>))
import Network.HTTP.Types
request <- parseUrl $ "someUrl"
res <- withManager $ httpLbs request
putStrLn $ show $ responseCookieJar res
Instead of printing responseCookieJar I want to get a value from it. This http://hackage.haskell.org/package/http-conduit-2.1.2/docs/Network-HTTP-Conduit.html#t:CookieJar implies that it's not possible. So I figure I have to parse (by regexp) it as a string. But there must a standard way like getting a value by its key.
Isn't there?

You can call destroyCookieJar to break it into the individual Cookies, and then search that list.

You can use destroyCookieJar to turn it into a list of Cookies, which you can then inspect via various field accessors.
The two most useful for keys are probably cookie_name and cookie_path. So you might do something like
filter (\c -> cookie_name c == pack "foo") . destroyCookieJar
(using pack from Data.Bytestring.Char8)
Or if there are a lot of cookies and you want to do multiple queries, you may want to build something like a Map from name to cookie first.

Related

Why can a parameter accept any construction of a typeclass but its value can't be constructed conditionally?

I'm fairly new to Haskell, though not to programming, and I've been using the req library to perform HTTPS requests.
In order to retain some generality, there will be two types of request - one to create a document (via HTTP POST) and another to update a document (via HTTP PATCH, using a non-empty monoid in the updateMask parameter).
I can infer the HTTP verb from whether updateMask == mempty, but this won't compile because POST and PATCH are different data declarations (although both are valid as the first parameter of req because they are instances of HttpMethod.
getSaveEventRequestResponse :: Text -> Option Https -> Document -> IO IgnoreResponse
getSaveEventRequestResponse authToken updateMask document =
runReq defaultHttpConfig $
req
(if updateMask == mempty
then POST
else PATCH)
(https "test.example.com" /: "api" /: "projects" /: "myproject")
(ReqBodyJson document)
ignoreResponse $
oAuth2Bearer (encodeUtf8 authToken) <> updateMask
If I swap out the if conditional for either one of POST or PATCH the code compiles without error.
Is there a way to make the compiler allow this conditional response or do I have to duplicate this function, one using the POST variant and another using the PATCH?
Edit for the benefit of anyone who comes to this and tries to use the same code:
The condition I used (updateMask == mempty) is not actually valid here, but that's not relevant to the question. The question stands if this condition is replaced by True or False.
Edit 2 regarding the linked question. While I now, having got the answer, see how closely linked it is, it relies on having already considered partial application. While the principle is the same, the introduction of partial application makes it difficult for a beginner with Haskell to apply the answer there to this context.
A possible solution is to use
(if updateMask == mempty then req POST else req PATCH) other args here
This is because
req :: (MonadHttp m, HttpMethod method, HttpBody body,
HttpResponse response,
HttpBodyAllowed (AllowsBody method) (ProvidesBody body))
=> method
-> Url scheme
-> body
-> Proxy response
-> Option scheme
-> m response
Now, AllowsBody POST and AllowsBody PATCH are equal, since both are defined as 'CanHaveBody. Therefore, both req POST and req PATCH can share a common type:
req POST, req PATCH
:: (MonadHttp m, HttpBody body,
HttpResponse response,
HttpBodyAllowed 'CanHaveBody (ProvidesBody body))
=> Url scheme
-> body
-> Proxy response
-> Option scheme
-> m response
Having the same type, they can be used in the two branches of the same if then else.

Modeling a POST API in a type safe way

Haskell beginner here, trying to wrap a HTTP REST API in a safe way and with automatic Aeson decoding of return values. I started with a Haskell function for every API call. It was a bit boilerplateish, but ok.
Looking to improve things I wanted to turn each API call into a data type of its own. For example for logging in, I would model that as Login type that specifies the method, Credentials type for method parameters and LoginReponse for the result of the API call. Parameters and response types of course have corresponding FromJSON and ToJSON instances.
For two API calls it looks something like this (using GADTs):
data Void = Void
data Credentials = Credentials {...}
data LoginResponse = LoginResponse {...}
data LogoutResponse = LogoutResponse {...}
data Command a where
Login :: Credentials -> Command LoginResponse
Logout :: Void -> Command LogoutResponse
execute :: FromJSON a => Command a -> IO a
execute cmd = do
manager <- newManager tlsManagerSettings
let request = buildHttpRequest cmd
result <- httpLbs request manager
let body = responseBody result
let parsed = fromJust $ decode body
return parsed
This works great for my use case - I can introspect Commands before executing them, I can't construct invalid API calls and Aeson knows how to decode the return values!
Only problem with this approach is that I have to keep all of my Commands in a single file under single data declaration.
I'd like to move method definitions (in my example Login and Logout) to separate modules, but to keep the execute function similar, and of course keep the type safety and Aeson decoding.
I've tried to make something using type classes, but got nowhere.
Any tips how to do that are welcome!
Since the only thing you do differently in execute for different commands is call buildHttpRequest, I propose the following alternate data type:
type Command a = Tagged a HttpRequest
(I don't know the return type of buildHttpRequest, so I made something up and assumed it returned an HttpRequest. Hopefully the idea will be clear enough even though I'm sure I got this part wrong.) The Tagged type comes from tagged, and lets you attach a type to a value; it is the urphantom type. In our case, we will use the attached type to decide how to decode JSON in the execute step.
The type of execute needs a slight modification to demand that the attached type can be decoded:
execute :: FromJSON a => Command a -> IO a
However, its implementation remains basically unchanged; simply replace buildHttpRequest with untag. These commands are not conveniently introspectable, but you will be able to split things up along module boundaries; e.g.
module FancyApp.Login (Credentials(..), LoginResponse(..), login) where
import FancyApp.Types
data Credentials = Credentials
data LoginResponse = LoginResponse
login :: Credentials -> Command LoginResponse
login = {- the old implementation of buildHttpRequest for Login -}
module FancyApp.Logout (LogoutResponse(..), logout) where
import FancyApp.Types
data LogoutResponse = LogoutResponse
logout :: Command LogoutResponse
logout = {- the old implementation of buildHttpRequest for Logout -}

How can I extract the tags and content of children using xml-conduit?

UPDATE: After many different attempts I have for now concluded that the behaviour seen below is expected and that I am only running into difficulties because I am using ToJson later on. Will update if I solve it completely.
==============================================================
I am trying to use xml-conduit to achieve this:
go down the cursor of a document to the element of an html document.
treat any descendants of this node as text. i.e. don't only get the content as text, but also the tags themselves.
so for example, I edited this example as per my comments below
<ol>
<li class="c1">
this is really "good work" <i>John</i>.
</li>
</ol>
should return
"<li class="c1"> this is really "good work" <i>John</i> </li>"
Whereas I'm getting
" "\u003cli class=\"c1\"\u003e this is really "good work"\u003ci\u003eJohn\u003c/i\u003e\u003c/li\u003e
So there is something going on within the tags that is different from what is happening to the content. I think perhaps the ToHtml instance isnt quite what i want really. I just want to collapse all descendants, turn their tags and content into text. I can't find a way though.
import Text.Blaze.Html (toHtml, preEscapedToHtml)
import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
--import Text.Blaze.Html.Renderer.String (renderHtml)
--import Text.Blaze.Html.Renderer.Text (renderHtml)
import Data.Text.Encoding (decodeUtf8)
import Data.ByteString.Lazy (toStrict)
extractAllParas :: Cursor -> [ Text ]
extractAllParas c = do
let mt' = c $/ laxElement "body" &// laxElement "ol" &/ anyElement
mt = (map (decodeUtf8 . toStrict . renderHtml . toHtml . node) $ mt')
case mt of
[ "" ] -> []
paras -> formatParas paras
formatParas :: [ Text ] -> [ Text ]

GHCJS-DOM event guidance

I'm trying to understand how to create a GUI with GHCJS-DOM. I've been looking at the hello world example https://github.com/ghcjs/ghcjs-dom-hello, which is trivial. Adding new nodes is straightforward. What I can't do, and cannot work out from the library documentation (only signatures) is to add some events. For example add a new node to the body on a mouse click.
I wish to avoid using JS libraries like JQuery, because I want by GUI to be portable between GHC (webkit) and GHCJS.
Ultimately I'd like to be able to express a mouse event as a FRP Event, but I'll settle for one step at a time.
If anyone has any guidance I'd be most grateful. I've used haskell for a few years now, but this is my first venture into DOM.
You can get information about the DOM from a number of places including mozilla. Here is an example that adds an event handler for click events on the document body...
module Main (
main
) where
import Control.Applicative ((<$>))
import Control.Monad.Trans (liftIO)
import GHCJS.DOM
(enableInspector, webViewGetDomDocument, runWebGUI)
import GHCJS.DOM.Document (documentGetBody, documentCreateElement)
import GHCJS.DOM.HTMLElement (htmlElementSetInnerHTML, htmlElementSetInnerText)
import GHCJS.DOM.Element (elementOnclick)
import GHCJS.DOM.HTMLParagraphElement
(castToHTMLParagraphElement)
import GHCJS.DOM.Node (nodeAppendChild)
import GHCJS.DOM.EventM (mouseClientXY)
main = runWebGUI $ \ webView -> do
enableInspector webView
Just doc <- webViewGetDomDocument webView
Just body <- documentGetBody doc
htmlElementSetInnerHTML body "<h1>Hello World</h1>"
elementOnclick body $ do
(x, y) <- mouseClientXY
liftIO $ do
Just newParagraph <- fmap castToHTMLParagraphElement <$> documentCreateElement doc "p"
htmlElementSetInnerText newParagraph $ "Click " ++ show (x, y)
nodeAppendChild body (Just newParagraph)
return ()
return ()

Happstack middleware lack?

I have usual happstack case in which we have ServerPart Response MonadPlus in list and. Then msum Chooses the one that does not fail and response generated and returned.
I have opinion that some actions - like cheking cookies - preparing connection context (authorising authenticated user, implementing counts, etc...) should be done in any incoming request - without any path info even defined yet.
Maybe there's some buzzy word I still not knowing yet, specially for such kinds of staff. Could someone advice please?
If you want to take certain actions for every request, you can add them in the do statement before your routing code. For example:
module Main where
import Happstack.Server
main = simpleHTTP nullConf $ do incCounter
mUser <- checkUserAuth
resp <- msum [ part1
, part2
, part3 mUser
]
logResponse resp
return resp
That will always run incCounter and checkUserAuth. Then it will try the various routes.
If one of the routes matches, it will then call logResponse, and then finally return the resp which will be sent to the user.
Note that while incCounter and checkUserAuth will always be run, logResponse will only be run if one of the parts matches. If none do, then I am pretty sure the code will escape and return a 404. If you wanted logResponse to always run, then you could add a handler to the msum that always matches. For example:
resp <- msum [ part1
, part2
, part3 mUser
, notFound $ toResponse "Sorry, page not found."
]
That will almost always run. If one of the parts matches, but explicitly calls 'escape', then I am pretty sure logResponse still won't be run. There are ways of dealing with that as well.
But, the short answer is, if you want something to happen even time, just put it before your msum code.

Resources