![]() |
boost::taar::jsonrpc::endpoint — A JSON-RPC 2.0 method registry mounted on one HTTP route.
// In header: <boost/taar/jsonrpc/endpoint.hpp> template<typename... Context> class endpoint { public: // types typedef handler::contexts< Context... > contexts_type; typedef handler::contexts< Context..., request_scope > call_contexts; // Contexts a method callable may request: the endpoint's plus the per-request request_scope. typedef boost::beast::http::request< boost::beast::http::string_body > request_type; typedef boost::beast::http::response< boost::beast::http::string_body > response_type; // member classes/structs/unions // The HTTP handler to register on the session route. class handler_type { public: // types typedef endpoint::request_type request_type; // public member functions explicit handler_type(endpoint *); template<typename Contexts> awaitable< response_type > operator()(Contexts const &, request_type const &, matcher::context const &); // public data members static constexpr bool context_aware; }; // A registered in-flight request; unregisters on destruction. class scoped_request { public: // public member functions scoped_request(endpoint *, std::string, std::shared_ptr< request_scope >); scoped_request(scoped_request &&) noexcept; scoped_request(scoped_request const &) = delete; scoped_request & operator=(scoped_request const &) = delete; ~scoped_request(); // public data members std::shared_ptr< request_scope > scope; }; // public member functions endpoint() = default; endpoint(endpoint const &) = delete; endpoint & operator=(endpoint const &) = delete; template<typename Callable, typename... Providers> endpoint & method(std::string, Callable &&, Providers...); template<typename Callable, typename... Providers> endpoint & method(std::string, std::string, Callable &&, Providers...); void set_error_mapper(error_mapper); error_info map_failure(taar::failure const &) const; std::vector< method_info > methods() const; bool has_method(std::string const &) const; awaitable< std::optional< boost::json::value > > dispatch(contexts_type const &, envelope const &, request_type const &, matcher::context const &, std::string_view = {}); scoped_request begin_request(envelope const &, std::string_view, boost::asio::any_io_executor); std::size_t cancel(boost::json::value const &, std::string_view = {}); awaitable< std::optional< boost::json::value > > handle_json(contexts_type const &, boost::json::value const &, request_type const &, matcher::context const &); awaitable< response_type > handle(contexts_type const &, request_type const &, matcher::context const &); handler_type handler(); // public static functions template<typename T> static awaitable< T > run_scoped(std::shared_ptr< request_scope > const &, awaitable< T >); static response_type to_http(request_type const &, std::optional< boost::json::value >); static boost::json::value recoverable_id(boost::json::value const &); };
Register methods with method, then register handler() on a session route. The endpoint parses the request body, dispatches each envelope (single or batch) to the matching method, converts results and exceptions into response envelopes, and answers notifications with 202 Accepted and no body.
Method callables follow the same convention as handler::rest: leading parameters that request a context type in scope are injected, the rest come from rpc_arg providers in order. The template arguments name the context types the endpoint will see: the session's connection context, plus any keyed context added by handler::with_session around handler().
taar::jsonrpc::endpoint<conn_stats> rpc; rpc.method("add", "Add two integers", &add, rpc_arg("a"), rpc_arg("b")); rpc.method("history", &history); session.register_request_handler( method == http::verb::post && target == "/rpc", rpc.handler());
Behaviour notes:
Method names are case-sensitive; registering a name twice throws std::logic_error.
Unknown members of params are ignored. A params array binds positionally to the method's rpc_arg providers in order. Scalar params are reported as -32602.
All responses, including error envelopes, use HTTP status 200 with Content-Type: application/json. Notifications (no id) produce 202 with an empty body; so does a batch made only of notifications.
Exceptions thrown by method callables are wrapped as a boost::taar::failure and turned into error envelopes by the mapper installed with set_error_mapper (default: default_error_mapper). The mapper is also invoked for notifications so it can log, but its result is discarded.
endpoint public member functionsendpoint() = default;
endpoint(endpoint const &) = delete;
endpoint & operator=(endpoint const &) = delete;
template<typename Callable, typename... Providers> endpoint & method(std::string name, Callable && callable, Providers... providers);Register callable as method name with no description.
template<typename Callable, typename... Providers> endpoint & method(std::string name, std::string description, Callable && callable, Providers... providers);Register callable as method name with a description for generators.
void set_error_mapper(error_mapper mapper);Replace the failure-to-error mapping.
See default_error_mapper.
mapper is invoked as mapper(taar::failure const&) and returns the error_info to send. A mapper that throws falls back to default_error_mapper.
rpc.set_error_mapper([](taar::failure const& f) -> jsonrpc::error_info { if (auto const e = f.as<division_by_zero>()) return {-32001, e->what(), std::nullopt}; return jsonrpc::default_error_mapper(f); });
error_info map_failure(taar::failure const & f) const;Map a failure with the installed mapper (falls back to the default if the mapper throws).
std::vector< method_info > methods() const;Registration-time descriptions of all methods, in registration order.
bool has_method(std::string const & name) const;True if a method named name is registered.
awaitable< std::optional< boost::json::value > > dispatch(contexts_type const & ctxs, envelope const & env, request_type const & request, matcher::context const & mctx, std::string_view scope_key = {});Dispatch one parsed envelope.
Returns: |
The response envelope, or |
scoped_request begin_request(envelope const & env, std::string_view scope_key, boost::asio::any_io_executor executor);Register a request as in flight and create its request_scope.
Parameters: |
|
std::size_t cancel(boost::json::value const & id, std::string_view scope_key = {});Cancel every in-flight request with id under scope_key.
Awaits inside the callable are interrupted; the response is a -32800 error (JSON-RPC) or suppressed (MCP).
Returns: |
The number of requests cancelled. |
awaitable< std::optional< boost::json::value > > handle_json(contexts_type const & ctxs, boost::json::value const & body, request_type const & request, matcher::context const & mctx);Handle a parsed JSON body (single object or batch array).
Returns: |
The JSON to send back, or |
awaitable< response_type > handle(contexts_type const & ctxs, request_type const & request, matcher::context const & mctx);Handle a raw HTTP request: parse the body and wrap the JSON result.
handler_type handler();Returns the handler to register. The endpoint must outlive the session.
endpoint public static functionstemplate<typename T> static awaitable< T > run_scoped(std::shared_ptr< request_scope > const & scope, awaitable< T > op);Run op under scope's cancellation slot, so cancel() interrupts its awaits.
static response_type to_http(request_type const & request, std::optional< boost::json::value > out);Wrap an optional JSON result into the HTTP response shape used by this layer.
static boost::json::value recoverable_id(boost::json::value const & element);The id of an element that failed envelope validation, if it can be recovered.