Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How should communications errors be caught? #26

Open
timbod7 opened this issue Jun 23, 2015 · 7 comments
Open

How should communications errors be caught? #26

timbod7 opened this issue Jun 23, 2015 · 7 comments

Comments

@timbod7
Copy link

timbod7 commented Jun 23, 2015

I'm trying out this library (and purescript) for the first time. The only example of which I am aware is this:

https://github.com/slamdata/purescript-halogen/blob/master/examples/ajax/src/Main.purs

Because the AffJaxResponse type has a field containing the http status code, I had assumed that errors would be reflected into this field. If I modify the example, I can see that it is set on success:

handler :: forall eff. String -> E.Event (HalogenEffects (ajax :: AJAX | eff)) Input
handler code = E.yield SetBusy `E.andThen` \_ -> E.async compileAff
  where
  compileAff :: Aff (HalogenEffects (ajax :: AJAX | eff)) Input
  compileAff = do
    result <- post "http://try.purescript.org/compile/text" code
    liftEff $ trace ("status = " ++ show result.status)
    let response = result.response
    return case readProp "js" response <|> readProp "error" response of
      Right js -> SetResult js
      Left _ -> SetResult "Invalid response"

If however, I force an error to occur (eg by making the URL invalid), then the code aborts rather than handles the error, as shown in the javascript console.

POST http://try.purescript.zzz/compile/text net::ERR_NAME_NOT_RESOLVED
...
index.js:12251 Uncaught error in asynchronous code: AJAX request failed: POST http://try.purescript.zzz/compile/text

How should the example code be modified to capture errors such they the can can handled appropriately?

@garyb
Copy link
Member

garyb commented Jun 23, 2015

What you're seeing here is a little different from the usual usage of Aff/Affjax because you're in the Halogen Event monad, which runs the Aff for you, and therefore you lose the ability to handle the error with runAff. The error you're seeing in the console is being logged by Halogen.

If there is a response from the server then you will receive an AffjaxResponse and then can check the status code and headers, however reading from an invalid URL or attempting to contact a non-existent server will fail (I think, this is basically the underlying XHR behaviour).

Aff provides various other methods for error handling too though. For instance, you can catch errors by using attempt - which will make the computation return an Either rather than ever failing.

@timbod7
Copy link
Author

timbod7 commented Jun 24, 2015

Thanks. Using attempt addressed the problem.

The challenge here is knowing when exceptions may be thrown, and hence calling attempt is necessary.

@jdegoes
Copy link
Contributor

jdegoes commented Jun 24, 2015

The challenge here is knowing when exceptions may be thrown, and hence calling attempt is necessary.

I'd agree. I'd be open to a the idea of exposing connection errors in the type, rather than propagating them through Aff, although I think @garyb found that browsers don't really provide any data on the failure.

@garyb
Copy link
Member

garyb commented Jun 24, 2015

Yeah, unfortunately there is no info about what went wrong when a request fails via onerror, which is the case that needs catching with Aff.

I couldn't even find a good list of conditions in which it would fail this way - as far as I can tell it's whenever a response never comes back from the server, but there are myriad reasons why that might be.

@bbarker
Copy link

bbarker commented Jan 27, 2021

I was doing something quite similar with attempt (well, the polymorphic version: try), and even 404s appear to not be caught (which will temporarily break the widget in question until the parent reloads it) :

      resEi <- liftAff $ try $ AJ.get AJ.string $ urlToString jsonUrl
      -- ... snip ...
      let res = join $ lmap AJ.XHRError resEi
      in case res of
        Left err -> errorBox $ EX.error $
          "GET /api response failed to decode: " <> AJ.printError err
        Right response -> pure $ Tuple doi (Just $ readRecordJSON response.body)

@garyb
Copy link
Member

garyb commented Jan 27, 2021

A 404 won't raise this kind of error - it might be that the content returned with a 404 will not decode with the appropriate content type, and that is what is causing the error, but a 404 itself will just be treated like any other response. The error being talked about in this issue is when a request fails entirely - there's no response at all from the server.

@bbarker
Copy link

bbarker commented Jan 27, 2021

Ah, yes, the issue is that response.body is undefined. I'll open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants