### Install json-rpc-cxx using CMake Source: https://github.com/jsonrpcx/json-rpc-cxx/blob/master/README.md This snippet shows the standard CMake build process to install the json-rpc-cxx library. It involves creating a build directory, configuring the project with CMake, and then installing the library. Ensure you have CMake and a C++ compiler installed. ```bash mkdir build && cd build cmake .. sudo make install ``` -------------------------------- ### Create and Configure JSON-RPC 2.0 Server in C++ Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt Demonstrates how to create a JSON-RPC 2.0 server using jsonrpccxx. This includes registering methods (both with and without responses), handling various parameter types (positional, named), processing notifications, and managing batch requests. It uses a Calculator class as an example. ```cpp #include #include class Calculator { public: int Add(int a, int b) { return a + b; } double Divide(double a, double b) { if (b == 0) { throw jsonrpccxx::JsonRpcException( jsonrpccxx::invalid_params, "Division by zero" ); } return a / b; } void LogOperation(const std::string& operation) { std::cout << "Operation: " << operation << std::endl; } }; int main() { jsonrpccxx::JsonRpc2Server server; Calculator calc; // Register methods with named parameters server.Add("add", jsonrpccxx::GetHandle(&Calculator::Add, calc), {"a", "b"}); server.Add("divide", jsonrpccxx::GetHandle(&Calculator::Divide, calc), {"numerator", "denominator"}); // Register notification (no response) server.Add("log", jsonrpccxx::GetHandle(&Calculator::LogOperation, calc), {"operation"}); // Handle a request std::string request = R"({\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[5,3],\"id\":1})"; std::string response = server.HandleRequest(request); // Response: {"id":1,"jsonrpc":"2.0","result":8} // Handle named parameters std::string namedRequest = R"({\"jsonrpc\":\"2.0\",\"method\":\"divide\",\"params\":{\"numerator\":10.0,\"denominator\":2.0},\"id\":2})"; std::string namedResponse = server.HandleRequest(namedRequest); // Response: {"id":2,"jsonrpc":"2.0","result":5.0} // Handle notification (no id field) std::string notification = R"({\"jsonrpc\":\"2.0\",\"method\":\"log\",\"params\":[\"calculator started\"]})"; server.HandleRequest(notification); // Returns empty string // Handle batch request std::string batchRequest = R"([ {"jsonrpc":"2.0","method":"add","params":[1,2],"id":1}, {"jsonrpc":"2.0","method":"add","params":[3,4],"id":2} ])"; std::string batchResponse = server.HandleRequest(batchRequest); // Response: [{"id":1,"jsonrpc":"2.0","result":3},{"id":2,"jsonrpc":"2.0","result":7}] return 0; } ``` -------------------------------- ### JSON-RPC Client Initialization with Different Connectors in C++ Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt This C++ code demonstrates how to initialize a JSON-RPC client using both an in-memory connector for testing and an HTTP connector for production. It showcases the instantiation of `JsonRpc2Server`, `InMemoryConnector`, `HttpConnector`, and `JsonRpcClient`, along with a basic method call and error handling. ```cpp int main() { // Use in-memory connector for testing jsonrpccxx::JsonRpc2Server server; InMemoryConnector inMemoryConn(server); jsonrpccxx::JsonRpcClient inMemoryClient(inMemoryConn, jsonrpccxx::version::v2); // Use HTTP connector for production HttpConnector httpConn("http://localhost:8080/rpc"); jsonrpccxx::JsonRpcClient httpClient(httpConn, jsonrpccxx::version::v2); try { int result = httpClient.CallMethod(1, "calculate", {10, 5}); } catch (jsonrpccxx::JsonRpcException& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ``` -------------------------------- ### BatchClient - Execute Multiple RPC Calls in C++ Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt The BatchClient class allows sending multiple JSON-RPC calls as a single request to optimize network usage. It supports adding method calls (with positional or named parameters) and notifications to a batch request. The response can be parsed to retrieve individual results or identify errors. ```cpp #include #include class HttpConnector : public jsonrpccxx::IClientConnector { public: std::string Send(const std::string& request) override { // Send batch request to server return server_response; } }; int main() { HttpConnector connector; jsonrpccxx::BatchClient client(connector); // Build batch request jsonrpccxx::BatchRequest request; request.AddMethodCall(1, "add", {5, 3}) .AddMethodCall(2, "multiply", {4, 7}) .AddNamedMethodCall("req3", "divide", {{"numerator", 100.0}, {"denominator", 5.0}}) .AddNotificationCall("log", {"batch operation started"}) .AddMethodCall(4, "subtract", {10, 3}); try { // Send batch request jsonrpccxx::BatchResponse response = client.BatchCall(request); // Retrieve results by ID int addResult = response.Get(1); std::cout << "Add result: " << addResult << std::endl; // Output: 8 int multiplyResult = response.Get(2); std::cout << "Multiply result: " << multiplyResult << std::endl; // Output: 28 double divideResult = response.Get("req3"); std::cout << "Divide result: " << divideResult << std::endl; // Output: 20.0 int subtractResult = response.Get(4); std::cout << "Subtract result: " << subtractResult << std::endl; // Output: 7 // Check for errors if (response.HasErrors()) { std::vector invalidIndexes = response.GetInvalidIndexes(); std::cout << "Some requests failed" << std::endl; } } catch (jsonrpccxx::JsonRpcException& e) { std::cerr << "Batch error: " << e.what() << std::endl; } return 0; } ``` -------------------------------- ### Implement In-Memory Client Connector for Testing in C++ Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt This C++ code provides an in-memory client connector for testing JSON-RPC functionality. It implements the `IClientConnector` interface and its `Send` method, which directly calls the `HandleRequest` method of a `JsonRpcServer` instance. This allows for testing without actual network communication. ```cpp // In-memory connector for testing class InMemoryConnector : public jsonrpccxx::IClientConnector { public: explicit InMemoryConnector(jsonrpccxx::JsonRpcServer& server) : server(server) {} std::string Send(const std::string& request) override { return server.HandleRequest(request); } private: jsonrpccxx::JsonRpcServer& server; }; ``` -------------------------------- ### JsonRpc2Server - Handling JSON-RPC 2.0 Requests Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt The `JsonRpc2Server` class enables the creation and management of a JSON-RPC 2.0 server. It handles incoming requests, validates them against the protocol, routes them to registered methods, and returns appropriate responses or error messages. It supports single requests, batch requests, notifications, and both positional and named parameters. ```APIDOC ## JsonRpc2Server - Handle JSON-RPC 2.0 Requests ### Description Manages incoming JSON-RPC 2.0 requests and routes them to registered methods. Supports single requests, batch requests, notifications, and both positional and named parameters. ### Method POST (typically, for transporting requests over HTTP, though the `HandleRequest` method itself is synchronous and can be used with any transport) ### Endpoint `/` (or any transport-specific endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **request** (string) - Required - A JSON string representing a single JSON-RPC 2.0 request, a batch of requests, or a notification. **Example Single Request:** ```json { "jsonrpc": "2.0", "method": "add", "params": [5, 3], "id": 1 } ``` **Example Named Parameters Request:** ```json { "jsonrpc": "2.0", "method": "divide", "params": { "numerator": 10.0, "denominator": 2.0 }, "id": 2 } ``` **Example Notification:** ```json { "jsonrpc": "2.0", "method": "log", "params": ["calculator started"] } ``` **Example Batch Request:** ```json [ { "jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1 }, { "jsonrpc": "2.0", "method": "add", "params": [3, 4], "id": 2 } ] ``` ### Request Example ```cpp #include #include class Calculator { public: int Add(int a, int b) { return a + b; } double Divide(double a, double b) { if (b == 0) { throw jsonrpccxx::JsonRpcException( jsonrpccxx::invalid_params, "Division by zero" ); } return a / b; } void LogOperation(const std::string& operation) { std::cout << "Operation: " << operation << std::endl; } }; int main() { jsonrpccxx::JsonRpc2Server server; Calculator calc; server.Add("add", jsonrpccxx::GetHandle(&Calculator::Add, calc), {"a", "b"}); server.Add("divide", jsonrpccxx::GetHandle(&Calculator::Divide, calc), {"numerator", "denominator"}); server.Add("log", jsonrpccxx::GetHandle(&Calculator::LogOperation, calc), {"operation"}); std::string request = R"({\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[5,3],\"id\":1})"; std::string response = server.HandleRequest(request); std::cout << "Response: " << response << std::endl; std::string namedRequest = R"({\"jsonrpc\":\"2.0\",\"method\":\"divide\",\"params\":{\"numerator\":10.0,\"denominator\":2.0},\"id\":2})"; std::string namedResponse = server.HandleRequest(namedRequest); std::cout << "Response: " << namedResponse << std::endl; std::string notification = R"({\"jsonrpc\":\"2.0\",\"method\":\"log\",\"params\":[\"calculator started\"]})"; server.HandleRequest(notification); std::string batchRequest = R"([{\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[1,2],\"id\":1},{\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[3,4],\"id\":2}])"; std::string batchResponse = server.HandleRequest(batchRequest); std::cout << "Response: " << batchResponse << std::endl; return 0; } ``` ### Response #### Success Response (200) - **response** (string) - A JSON string representing the JSON-RPC 2.0 response for a single request or batch request. For notifications, an empty string is returned. **Example Single Response:** ```json { "id": 1, "jsonrpc": "2.0", "result": 8 } ``` **Example Batch Response:** ```json [ { "id": 1, "jsonrpc": "2.0", "result": 3 }, { "id": 2, "jsonrpc": "2.0", "result": 7 } ] ``` #### Error Response - **error** (object) - Contains error information if the request could not be processed. ```json { "jsonrpc": "2.0", "error": { "code": -32602, "message": "Invalid params" }, "id": 1 } ``` ``` -------------------------------- ### JsonRpcClient - Make Individual RPC Calls in C++ Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt The JsonRpcClient class facilitates making individual JSON-RPC calls to a server. It requires an IClientConnector implementation for transport and handles method calls with positional or named parameters, as well as notifications. Error handling for RPC exceptions is demonstrated. ```cpp #include #include #include // Example connector implementation class HttpConnector : public jsonrpccxx::IClientConnector { public: std::string Send(const std::string& request) override { // Send HTTP POST request to server // Return response as string return response_from_server; } }; int main() { HttpConnector connector; jsonrpccxx::JsonRpcClient client(connector, jsonrpccxx::version::v2); try { // Call method with positional parameters int result = client.CallMethod(1, "add", {5, 3}); std::cout << "Result: " << result << std::endl; // Output: 8 // Call method with named parameters double divResult = client.CallMethodNamed( 2, "divide", {{"numerator", 10.0}, {"denominator", 2.0}} ); std::cout << "Division result: " << divResult << std::endl; // Output: 5.0 // Send notification (no response expected) client.CallNotification("log", {"operation completed"}); // Call method with custom type struct Product { std::string id; double price; std::string name; }; Product product = client.CallMethod(3, "getProduct", {"product123"}); } catch (jsonrpccxx::JsonRpcException& e) { std::cerr << "RPC Error [" << e.Code() << "]: " << e.Message() << std::endl; } return 0; } ``` -------------------------------- ### Implement HTTP Client Connector using libcurl in C++ Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt This C++ code implements an HTTP client connector for JSON-RPC using the libcurl library. It overrides the `Send` method of `IClientConnector` to send POST requests with JSON payloads and handle responses. Initialization and cleanup of curl are managed in the constructor and destructor. ```cpp #include #include #include #include #include // HTTP connector using libcurl class HttpConnector : public jsonrpccxx::IClientConnector { public: HttpConnector(const std::string& url) : url(url) { curl_global_init(CURL_GLOBAL_DEFAULT); } ~HttpConnector() { curl_global_cleanup(); } std::string Send(const std::string& request) override { CURL* curl = curl_easy_init(); std::string response; if (curl) { struct curl_slist* headers = nullptr; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_perform(curl); curl_slist_free_all(headers); curl_easy_cleanup(curl); } return response; } private: std::string url; static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } }; ``` -------------------------------- ### C++ JsonRpcException for Server-Side Errors and Client-Side Handling Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt This C++ code defines a `BankingService` that throws `jsonrpccxx::JsonRpcException` for various error conditions, including invalid parameters, account not found (with custom error code -32001), and insufficient funds (with custom error code -32002). It also demonstrates how a `jsonrpccxx::JsonRpcClient` can catch these exceptions, access error codes, messages, and additional data. ```cpp #include #include #include #include #include // Define a custom error code for demonstration const int CUSTOM_ACCOUNT_NOT_FOUND = -32001; const int CUSTOM_INSUFFICIENT_FUNDS = -32002; class BankingService { public: double GetBalance(const std::string& accountId) { if (accountId.empty()) { throw jsonrpccxx::JsonRpcException( jsonrpccxx::invalid_params, "Account ID cannot be empty" ); } if (accounts.find(accountId) == accounts.end()) { nlohmann::json errorData = { {"accountId", accountId}, {"availableAccounts", std::vector{"acc1", "acc2"}} }; throw jsonrpccxx::JsonRpcException( CUSTOM_ACCOUNT_NOT_FOUND, // Custom error code "Account not found", errorData ); } return accounts[accountId]; } bool Transfer(const std::string& from, const std::string& to, double amount) { if (amount <= 0) { throw jsonrpccxx::JsonRpcException( jsonrpccxx::invalid_params, "Amount must be positive" ); } if (accounts.find(from) == accounts.end() || accounts.find(to) == accounts.end()) { throw jsonrpccxx::JsonRpcException( jsonrpccxx::invalid_params, "One or both accounts not found" ); } if (accounts[from] < amount) { nlohmann::json errorData = { {"available", accounts[from]}, {"requested", amount}, {"deficit", amount - accounts[from]} }; throw jsonrpccxx::JsonRpcException( CUSTOM_INSUFFICIENT_FUNDS, // Custom error code "Insufficient funds", errorData ); } accounts[from] -= amount; accounts[to] += amount; return true; } private: std::map accounts = {{"acc1", 1000.0}, {"acc2", 500.0}}; }; // Mocking an IClientConnector for in-memory testing class InMemoryConnector : public jsonrpccxx::IClientConnector { public: InMemoryConnector(jsonrpccxx::JsonRpcServer& server) : server_(server) {} virtual std::string Send(const std::string& request) override { return server_.HandleRequest(request); } private: jsonrpccxx::JsonRpcServer& server_; }; int main() { jsonrpccxx::JsonRpc2Server server; BankingService banking; // Registering methods with their parameter names server.Add("getBalance", jsonrpccxx::GetHandle(&BankingService::GetBalance, banking), {"accountId"}); server.Add("transfer", jsonrpccxx::GetHandle(&BankingService::Transfer, banking), {"from", "to", "amount"}); // Example requests triggering errors std::string request1 = R"({"jsonrpc":"2.0","method":"getBalance","params":["acc999"],"id":1})"; std::string response1 = server.HandleRequest(request1); // Expected response for request1: {"error":{"code":-32001,"data":{"accountId":"acc999","availableAccounts":["acc1","acc2"]},"message":"Account not found"},"id":1,"jsonrpc":"2.0"} std::cout << "Response 1: " << response1 << std::endl; std::string request2 = R"({"jsonrpc":"2.0","method":"transfer","params":["acc1","acc2",2000.0],"id":2})"; std::string response2 = server.HandleRequest(request2); // Expected response for request2: {"error":{"code":-32002,"data":{"available":1000.0,"deficit":1000.0,"requested":2000.0},"message":"Insufficient funds"},"id":2,"jsonrpc":"2.0"} std::cout << "Response 2: " << response2 << std::endl; // Client-side error handling example InMemoryConnector connector(server); jsonrpccxx::JsonRpcClient client(connector, jsonrpccxx::version::v2); try { // Attempting to call a method that will result in an error client.CallMethod(3, "getBalance", {"acc999"}); } catch (jsonrpccxx::JsonRpcException& e) { std::cout << "\nClient caught an exception:" << std::endl; std::cout << "Error code: " << e.Code() << std::endl; std::cout << "Message: " << e.Message() << std::endl; std::cout << "Type: " << e.Type() << std::endl; if (!e.Data().is_null()) { std::cout << "Data: " << e.Data().dump(2) << std::endl; // Pretty print JSON data } } catch (const std::exception& e) { std::cerr << "An unexpected error occurred: " << e.what() << std::endl; } return 0; } ``` -------------------------------- ### Custom Type Serialization for JSON-RPC in jsonrpc-cxx Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt This snippet demonstrates how to map C++ structs to JSON for use in JSON-RPC methods. By utilizing nlohmann's JSON library macros (`NLOHMANN_JSON_SERIALIZE_ENUM`, `to_json`, `from_json`), the framework automatically handles the conversion between JSON objects and C++ structures. This is essential for passing complex data types as parameters or return values. ```cpp #include #include #include #include // Define custom types enum class Status { Active, Inactive, Pending }; struct User { std::string id; std::string name; int age; Status status; }; // Define JSON serialization NLOHMANN_JSON_SERIALIZE_ENUM(Status, { {Status::Active, "active"}, {Status::Inactive, "inactive"}, {Status::Pending, "pending"} }) inline void to_json(nlohmann::json& j, const User& u) { j = nlohmann::json{ {"id", u.id}, {"name", u.name}, {"age", u.age}, {"status", u.status} }; } inline void from_json(const nlohmann::json& j, User& u) { j.at("id").get_to(u.id); j.at("name").get_to(u.name); j.at("age").get_to(u.age); j.at("status").get_to(u.status); } // Service implementation class UserService { public: bool CreateUser(const User& user) { users[user.id] = user; return true; } User GetUser(const std::string& id) { if (users.find(id) == users.end()) { throw jsonrpccxx::JsonRpcException( jsonrpccxx::invalid_params, "User not found" ); } return users[id]; } std::vector GetAllUsers() { std::vector result; for (const auto& pair : users) { result.push_back(pair.second); } return result; } private: std::map users; }; int main() { // Server setup jsonrpccxx::JsonRpc2Server server; UserService userService; server.Add("createUser", jsonrpccxx::GetHandle(&UserService::CreateUser, userService), {"user"}); server.Add("getUser", jsonrpccxx::GetHandle(&UserService::GetUser, userService), {"id"}); server.Add("getAllUsers", jsonrpccxx::GetHandle(&UserService::GetAllUsers, userService), {}); // Example request with custom type std::string createRequest = R"({ "jsonrpc":"2.0", "method":"createUser", "params":[{"id":"user1","name":"John Doe","age":30,"status":"active"}], "id":1 })"; std::string response = server.HandleRequest(createRequest); // Response: {"id":1,"jsonrpc":"2.0","result":true} return 0; } ``` -------------------------------- ### Bind C++ Functions and Methods to RPC Handlers in jsonrpc-cxx Source: https://context7.com/jsonrpcx/json-rpc-cxx/llms.txt The GetHandle function in jsonrpc-cxx creates type-safe wrappers for C++ functions, member functions, and lambdas. It ensures compile-time parameter type checking and runtime validation, automatically generating JSON-RPC errors for mismatched types. This function is crucial for exposing C++ logic as RPC services. ```cpp #include #include #include #include // Free function int GlobalAdd(int a, int b) { return a + b; } // Class with methods class MathService { public: double Multiply(double a, double b) { return a * b; } std::vector Range(int start, int end) { std::vector result; for (int i = start; i <= end; i++) { result.push_back(i); } return result; } void Reset() { counter = 0; } private: int counter = 0; }; int main() { jsonrpccxx::JsonRpc2Server server; MathService mathService; // Bind free function server.Add("globalAdd", jsonrpccxx::GetHandle(&GlobalAdd), {"x", "y"}); // Bind member function server.Add("multiply", jsonrpccxx::GetHandle(&MathService::Multiply, mathService), {"a", "b"}); // Bind member function that returns array server.Add("range", jsonrpccxx::GetHandle(&MathService::Range, mathService), {"start", "end"}); // Bind notification (void return) server.Add("reset", jsonrpccxx::GetHandle(&MathService::Reset, mathService), {}); // Bind lambda auto customHandler = jsonrpccxx::GetHandle( std::function( [](std::string name, int count) { return name + " " + std::to_string(count); } ) ); server.Add("format", customHandler, {"name", "count"}); // Test requests std::string request1 = R"({"jsonrpc":"2.0","method":"multiply","params":[3.5,2.0],"id":1})"; std::cout << server.HandleRequest(request1) << std::endl; // Output: {"id":1,"jsonrpc":"2.0","result":7.0} std::string request2 = R"({"jsonrpc":"2.0","method":"range","params":[1,5],"id":2})"; std::cout << server.HandleRequest(request2) << std::endl; // Output: {"id":2,"jsonrpc":"2.0","result":[1,2,3,4,5]} return 0; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.