Boost C++ Libraries

PrevUpHomeNext

Class template endpoint

boost::taar::jsonrpc::endpoint — A JSON-RPC 2.0 method registry mounted on one HTTP route.

Synopsis

// 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 &);
};

Description

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 functions

  1. endpoint() = default;
  2. endpoint(endpoint const &) = delete;
  3. endpoint & operator=(endpoint const &) = delete;
  4. template<typename Callable, typename... Providers> 
      endpoint & method(std::string name, Callable && callable, 
                        Providers... providers);
    Register callable as method name with no description.
  5. 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.
  6. 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);
    });
    

  7. 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).
  8. std::vector< method_info > methods() const;
    Registration-time descriptions of all methods, in registration order.
  9. bool has_method(std::string const & name) const;
    True if a method named name is registered.
  10. 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 std::nullopt for a notification.

  11. 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:

    env

    The request envelope (notifications get a scope but are not registered).

    scope_key

    Namespace for ids, e.g. the MCP session id, so that equal ids from different clients do not collide.

    executor

    Executor on which cancellation is emitted.

  12. 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.

  13. 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 std::nullopt when nothing should be sent (notification, or a batch of notifications).

  14. 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.
  15. handler_type handler();
    Returns the handler to register. The endpoint must outlive the session.

endpoint public static functions

  1. template<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.
  2. 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.
  3. 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.

PrevUpHomeNext