layer1capital / easy-jsonrpc

Rust crate for generating jsonrpc apis from trait definitions
Apache License 2.0
5 stars 4 forks source link

Is it possible to return an error that occurs within a procedure to a client? #9

Open travispaul opened 2 years ago

travispaul commented 2 years ago

I'm probably missing something obvious, but I'm struggling to figure out how to return an error from within the procedure on the RPC server so that they're sent back to the client. I was hoping I to utilize easy_jsonrpc::Error but that doesn't seem to be handled specially (or I'm holding it wrong) and errors are returned in the result member instead of an error member.

I'm specifically looking to return an custom error member as mentioned by the JSON RPC spec, but I've only been able to return result:

error This member is REQUIRED on error. This member MUST NOT exist if there was no error triggered during invocation. The value for this member MUST be an Object as defined in section 5.1.

I've observed such errors being return in the event of an RPC error (invalid params, method doesn't exist, etc) but would like to return my own as well.

use easy_jsonrpc::{Handler, MaybeReply, serde_json::json, Error, ErrorCode};

#[easy_jsonrpc::rpc]
pub trait Example {
    fn fault(&self, fail: bool) -> Result<String, Error>;
}

struct ExampleImpl;

impl Example for ExampleImpl {
    fn fault(&self, fail: bool) -> Result<String, Error> {
        // manually triggering an error based on a bool but this would typically 
        // occur as the result of some real error such as an ID that doesn't exist
        if fail {
            return Err(Error {
                code: ErrorCode::ServerError(123),
                message: "oof".to_string(),
                data: None
            })
        }
        Ok("ok".to_string())
    }
}

fn main() {
    let handler = &ExampleImpl {} as &dyn Example;

    let response = handler.handle_request(json!({
        "jsonrpc": "2.0",
        "method": "fault",
        "params": [true],
        "id": 1
    }));

    // response:
    // {
    //   "id": 1,
    //   "jsonrpc": "2.0",
    //   "result": {
    //     "Err": {
    //       "code": 123,
    //       "message": "oof"
    //     }
    //   }
    //}

    let expected = json!({
        "jsonrpc": "2.0",
        "error": {
            "code": 123,
            "message": "oof"
        },
        "id": 1
    });

    assert_eq!(response, MaybeReply::Reply(expected));
}

Any guidance on achieving those results are greatly appreciated!

bddap commented 2 years ago

Unfortunately this library doesn't support that feature at the moment, though I'd like it if it did. Getting this to work in easy_jsonrpc will require changes to the library.

travispaul commented 2 years ago

Thanks for confirming @bddap, I think I can handle this in my application.