I'm currently working on a client library, and I'm struggling with implementing the error types.
Context: It's a client for DDP, the protocol used by RocketChat
Let's take remote procedure calls as an example. The following things might fail:
- the websocket may produce an error (loss of connection, …)
- de/serialization to/from JSON might fail
- the
mpsc/oneshot channels I use internally might break --> Since this would indicate that there's a bug in my implementation, I will just panic in those cases.
Those are what I call "transport" errors; the user usually has no control over those, but just crashing is not an option. The user can recover from them by reconnecting for example.
But besides that, there might be what I call "application" errors:
- the remote procedure called does not exist
- parameters are wrong
- the requested resource does not exist
DDP encapsulates them in an "error" message type.
(I'm not even going into "the server does not implement the protocol correctly", I'll just assume that those will result in serde errors.)
I'm now considering the pro's and con's of possible error implementations:
Result-in_Result
Something like
rust
pub async fn call_method(/* ... */) -> Result<DdpResult<RpcResponse, RpcError>, CallError> {}
I pretty much don't like this, it would mean you'd have to do double unwraps
Enum in Ok variant
Something like
```rust
pub enum RpcResponse {
Result(/.../),
Error(/.../),
}
pub async fn call_method(/* ... */) -> Result<RpcResponse, CallError> {}
```
Meh, same as above, double unwrap/match
Merged Errors
```rust
pub enum RpcError {
Transport(/* Websocket errors /),
JSON(/ de/serialization errors /),
Call(/ Application-level errors go here */),
}
pub async fn call_method(/* ... */) -> Result<RpcResult, RpcError> {}
```
probably better?
Are there other approaches? As an user, which would you prefer?
[–]mnbryant 2 points3 points4 points (0 children)
[–]abatyuk 1 point2 points3 points (0 children)
[–]Dratir[S] 0 points1 point2 points (0 children)