Composable Error Handling In Real World


#1

Suppose I want to wrap bs-fetch (in a React hook). Suppose I want the result to peruse Result.t, like Relude.AsyncResult does. Suppose that then I want to use decco for decoding (it speaks in Result, nice).

Suppose also that I’ve read Composable Error Handling in OCaml and want to use polymorphic variants for errors. Here are the issues I’ve met so far:

  1. bs-fetch raises exceptions. Catching them is not hard, but distinguishing individual errors by messages is a little too fragile, so the best I can do is just [`FetchError(string)], right? And error messages coming from libs are not always good to show to users: they’re not localizable, they can contain sensitive info, and they couple presentation to the innards.
  2. Decco just uses records for errors. Those can be mapped to polymorphic variants, I guess, but it looks like it’s going to be one variant as well, e.g. [`DecodingError(Decco.decodeError)].

So at this point, it’s just 2 variants. Maybe 3, if I add a validation step:

[>
  `FetchError(string),
  `DecodingError(Decco.decodeError),
  `ValidationError(validationError),
]

Questions:

  1. Do you guys think those variants are granular enough?
  2. Is it even worth it like that? )
  3. Can we expect more libraries supporting this pattern?

(I know, I know, answers like these would probably be closed over at StackOverflow :smile:)


#2

Good points! You may want to keep track of the exact errors despite not showing them to users, because you may want to log them. In real-world apps you would certainly want to log errors.

But taking a step back–I think the correct practice is to let the caller (at least one level up the stack) deal with the errors of the current level. For example, they can decide whether to retry the action or not. So it is important to return something, and your above error type looks good for that.


#3

Yeah, great point about logging, I’ve forgotten about that.

Thank you, I think I’ll go with that.

BTW, if I were to publish the useFetch hook (which I plan), do you think it makes sense to expose a lone `UseFetch__FetchError type? (I presume it does if the API uses Result.t.)


#4

It makes sense to have polyvariant case like that, for sure. Now as to the naming, UseFetch__FetchError seems a little clunky. I’m undecided on whether we should be trying to ‘namespace’ polyvariants like that–they are meant to be globally scoped. Perhaps just `FetchError?


#5

It does feel clunky, but what if several libraries expose `FetchError? Then again, maybe opening more than one module that does fetching is not that likely.


#6

Even if you had two modules that use the same polyvariant tag, it would only be a problem if you’d deal with it at the same place but still wanted to distinguish the two which is kind of unlikely because they would probably be similar given they share the same name.
I really like how convenient and ready to use Decco is, but I think it would benefit a lot from having the same kind of error handling bs-decode has. Decco ppx using bs-decode under the hood would be totally awesome.


#7

I really like the idea of a decco-like code generator for bs-decode, but alas I am not a PPX master and I haven’t really looked into it (yet). If anyone is interested in contributing something like that to bs-decode, I’m very open to it!


#8

Yeah, I’m no expert either, so at that point, I have no idea whether it’s simpler/better to contribute to decco or to bs-decode :grin:. But I’ll look into it once I have time.

PS. Error handling in bs-decode looks pretty thorough :+1:.


#9

Unfortunately I’m no expert either and especially no ppx expert, but I think having a de facto standard lib for decoding in Reason would be totally awesome so I’d happily contribute. If you’re really open to it I can try to dig the ppx issue and see what I can come up with. Plus having encode in bs-decode would be cool too.
We probably need more standards in Reason anyway so new comers don’t spend too much time thinking about every little brick in the stack.


#10

I am open, just give me some time to finish with useFetch. I’m taking my sweet time, for I don’t code all that much outside of my day job, and my day job has nothing to do with Reason so far (hopefully that will change :D). So, if you want ppx for bs-decode done ASAP, I guess your best bet is to start reading up on ppx yourself. If you’re willing to wait, I was planning to learn ppx anyway, so why not do it sooner. But again, it probably won’t be extremely fast, what with my lack of CS background and no experience with compilers, ASTs, and whatnot.

And sure, I agree that a standard decoding solution would be great for newcomers and generally for anyone trying to get things done.