purescript-contrib/purescript-affjax

Requestable instance for DecodeJson

Closed this issue · 6 comments

Could types that already implement EncodeJson implement Requestable, and DecodeJson implement Respondable?

Something like this (quick sketch, might not compile):

instance respondableDecodeJson :: DecodeJson t => Respondable t where
  fromResponse content = do
    json <- fromResponse content
    case decodeJson json of
      Left err -> throwError (pure (JSONError err))
      Right x -> pure x
  responseType =
    Tuple (Just applicationJSON) JSONResponse

Does this sound good? I could submit a PR.

OK, after having tried this out in affjax, it might not be realistic with the design of Respondable. This instance would cause overlapping instances all over the place.

My original problem was orphan instances - I wanted to define an instance of Respondable for any value that had an DecodeJson instance. I'll try some newtype trickery to solve it instead.

It'll work out, closing this. :)

garyb commented

Yeah, unfortunately having instances just based on a constraint don't really work out as you found. If this is for hyper, perhaps it could provide those implementations above as helper functions for writing the instances though? As then users could just do something like:

instance respondableMyValue :: Respondable MyValue where
  fromResponse = fromJsonResponse
  responseType = jsonResponseType

Yes, it's for the Hyper client lib I'm working on. It turned out I didn't really need that general Respondable instances for DecodeJson constrained types. I could instead use Respondable and DecodeJson directly in a less general instance of my HasClient class, and stitch it together like this:

instance hasClientsHandlerJson :: (DecodeJson b)
                                  => HasClients (Handler "GET" Json b) (Aff (ajax :: AJAX | e) b) where
  getClients _ req = do
    r <- affjax (toAffjaxRequest req)
    case decodeJson r.response of
      Left err -> throwError (error err)
      Right x -> pure x

There will be more instances of HasClient (Handler ...) for other content types (this is only Json), but that's necessary anyway, I suspect. This example might not make sense to you out-of-context, sorry for that. I'll publish the source code soon. 😄

garyb commented

Ah cool, and yeah I see where you're coming from :) - as long as you know about the DecodeJson instance you can apply it "manually" since there's a Respondable for Json.

Exactly! 👍