From a20ba207d25a9ab496518e84ec0c28b2d8d25ad7 Mon Sep 17 00:00:00 2001 From: Kim De Mey Date: Mon, 4 Mar 2024 09:19:28 +0100 Subject: [PATCH] Introduce custom application error with optional data object (#216) This addresses two items: - Use ApplicationError instead of InvalidRequest for custom application errors. Avoiding confusing regarding the usage of InvalidRequest (although the actual error code used could/would be different). - Allow for defining an optional data object that gets returned in the error response, as per json-rpc specification. --- json_rpc/errors.nim | 17 ++++++++++++++--- json_rpc/router.nim | 9 +++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/json_rpc/errors.nim b/json_rpc/errors.nim index 0b9aaca..7ec2a98 100644 --- a/json_rpc/errors.nim +++ b/json_rpc/errors.nim @@ -1,5 +1,5 @@ # json-rpc -# Copyright (c) 2019-2023 Status Research & Development GmbH +# Copyright (c) 2019-2024 Status Research & Development GmbH # Licensed under either of # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * MIT license ([LICENSE-MIT](LICENSE-MIT)) @@ -7,6 +7,10 @@ # This file may not be copied, modified, or distributed except according to # those terms. +{.push raises: [].} + +import results, json_serialization + type JsonRpcError* = object of CatchableError ## Base type of all nim-json-rpc errors @@ -28,8 +32,7 @@ type RpcAddressUnresolvableError* = object of JsonRpcError InvalidRequest* = object of JsonRpcError - ## This could be raised by request handlers when the server - ## needs to respond with a custom error code. + ## raised when the server recieves an invalid JSON request object code*: int RequestDecodeError* = object of JsonRpcError @@ -38,3 +41,11 @@ type ParamsEncodeError* = object of JsonRpcError ## raised when fail to encode RequestParamsTx + ApplicationError* = object of JsonRpcError + ## Error to be raised by the application request handlers when the server + ## needs to respond with a custom application error. The error code should + ## be outside the range of -32768 to -32000. A custom JSON data object may + ## be provided. + code*: int + message*: string + data*: results.Opt[JsonString] diff --git a/json_rpc/router.nim b/json_rpc/router.nim index 741bb64..a3dad24 100644 --- a/json_rpc/router.nim +++ b/json_rpc/router.nim @@ -58,6 +58,9 @@ func serverError(msg: string, data: JsonString): ResponseError = func somethingError(code: int, msg: string): ResponseError = ResponseError(code: code, message: msg) +func applicationError(code: int, msg: string, data: Opt[JsonString]): ResponseError = + ResponseError(code: code, message: msg, data: data) + proc validateRequest(router: RpcRouter, req: RequestRx): Result[RpcProc, ResponseError] = if req.jsonrpc.isNone: @@ -131,9 +134,15 @@ proc route*(router: RpcRouter, req: RequestRx): try: let res = await rpcProc(req.params) return wrapReply(res, req.id) + except ApplicationError as err: + return wrapError(applicationError(err.code, err.msg, err.data), req.id) except InvalidRequest as err: + # TODO: deprecate / remove this usage and use InvalidRequest only for + # internal errors. return wrapError(err.code, err.msg, req.id) except CatchableError as err: + # Note: Errors that are not specifically raised as `ApplicationError`s will + # be returned as custom server errors. let methodName = req.meth.get # this Opt already validated debug "Error occurred within RPC", methodName = methodName, err = err.msg