diff --git a/src/rpc/common/Validators.h b/src/rpc/common/Validators.h index 63888f22..41546c68 100644 --- a/src/rpc/common/Validators.h +++ b/src/rpc/common/Validators.h @@ -377,6 +377,36 @@ private: validator_; }; +/** + * @brief A meta-validator that wrapp other validator to send the customized + * error + */ +template +class WithCustomError final +{ + Requirement requirement; + RPC::Status error; + +public: + /** + * @brief Constructs a validator that calls the given validator "req" and + * return customized error "err" + */ + WithCustomError(Requirement req, RPC::Status err) + : requirement{std::move(req)}, error{err} + { + } + + [[nodiscard]] MaybeError + verify(boost::json::value const& value, std::string_view key) const + { + if (auto const res = requirement.verify(value, key); not res) + return Error{error}; + + return {}; + } +}; + /** * @brief A meta-validator that allows to specify a custom validation function */ diff --git a/unittests/rpc/BaseTests.cpp b/unittests/rpc/BaseTests.cpp index 3693f5c0..c5d320d7 100644 --- a/unittests/rpc/BaseTests.cpp +++ b/unittests/rpc/BaseTests.cpp @@ -258,6 +258,36 @@ TEST_F(RPCBaseTest, IfTypeValidator) ASSERT_FALSE(spec.validate(failingInput)); } +TEST_F(RPCBaseTest, WithCustomError) +{ + auto const spec = RpcSpec{ + {"transaction", + WithCustomError{ + Uint256HexStringValidator, + RPC::Status{ripple::rpcBAD_FEATURE, "MyCustomError"}}}, + {"other", + WithCustomError{ + Type{}, + RPC::Status{ripple::rpcALREADY_MULTISIG, "MyCustomError2"}}}}; + + auto const passingInput = json::parse( + R"({ "transaction": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", "other": "1"})"); + ASSERT_TRUE(spec.validate(passingInput)); + + auto failingInput = json::parse( + R"({ "transaction": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515B"})"); + auto err = spec.validate(failingInput); + ASSERT_FALSE(err); + ASSERT_EQ(err.error().message, "MyCustomError"); + ASSERT_EQ(err.error(), ripple::rpcBAD_FEATURE); + + failingInput = json::parse(R"({ "other": 1})"); + err = spec.validate(failingInput); + ASSERT_FALSE(err); + ASSERT_EQ(err.error().message, "MyCustomError2"); + ASSERT_EQ(err.error(), ripple::rpcALREADY_MULTISIG); +} + TEST_F(RPCBaseTest, CustomValidator) { // clang-format off