{"id":15724702,"url":"https://github.com/davenchy/general_json_rpc","last_synced_at":"2026-03-02T09:01:45.065Z","repository":{"id":42440778,"uuid":"478369110","full_name":"Davenchy/general_json_rpc","owner":"Davenchy","description":"This package will help you to invoke methods across network using any protocol, This package encode and decode your requests and responses to and from bytes so you can send it any where using any protocol, This package is implementing json-rpc v2.0","archived":false,"fork":false,"pushed_at":"2022-04-29T07:48:02.000Z","size":32,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-18T16:45:57.643Z","etag":null,"topics":["dart","flutter","json","json-rpc2","rpc"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Davenchy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-04-06T02:08:33.000Z","updated_at":"2024-05-22T02:56:32.000Z","dependencies_parsed_at":"2022-09-09T16:31:29.260Z","dependency_job_id":null,"html_url":"https://github.com/Davenchy/general_json_rpc","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Davenchy/general_json_rpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davenchy%2Fgeneral_json_rpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davenchy%2Fgeneral_json_rpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davenchy%2Fgeneral_json_rpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davenchy%2Fgeneral_json_rpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Davenchy","download_url":"https://codeload.github.com/Davenchy/general_json_rpc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davenchy%2Fgeneral_json_rpc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29996266,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","flutter","json","json-rpc2","rpc"],"created_at":"2024-10-03T22:17:39.243Z","updated_at":"2026-03-02T09:01:44.021Z","avatar_url":"https://github.com/Davenchy.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GeneralJsonRpc\n\nGeneralJsonRpc is a package that implements json-rpc v2.0 and its purpose is to ease invoking methods and exchange data throw network\n\nthe package is focusing on encoding and decoding json-rpc messages to and from bytes\nto ease sending and receiving using any protocol\n\n## A Quick Guide\n\nIn this guide you will create a server and client sides application that invokes methods throw\ntcp sockets\n\nlets start\n\n- First on the server side we will define 3 methods [sum, print, quit]\n  \n  - The `sum` method will get numbers list and returns their sum\n  \n  - The `print` method will get a parameter named `message` and print its content on the server side\n  \n  - The `quit` method will end the application by executing `exit(0);`\n\n```dart\nimport 'dart:io';\nimport 'package:general_json_rpc/general_json_rpc.dart';\n\nvoid main() {\n  server();\n  client();\n}\n```\n\n```dart\nvoid server() async {\n  final server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);\n  print('[server] Server is running on port 8081');\n\n  // create MethodRunner to define the rpc methods\n  final runner = MethodRunner();\n\n  // now lets define the 3 methods\n  runner.register\u003cint\u003e('sum', (numbers) =\u003e numbers.reduce((a, b) =\u003e a + b));\n  runner.register\u003cvoid\u003e('print', (p) =\u003e print(p['message']));\n\n  runner.register('quit', (_) {\n    print('[server] Quit');\n    exit(0);\n  });\n\n  // now lets listen for new clients\n  await for (final Socket client in server) {\n    print('[server] new client');\n    client.listen(\n      (bytes) async {\n        // converts bytes into [RpcObject]\n        final rpcObject = RpcObject.decode(bytes);\n\n        // now lets handle all cases\n        final response = await RpcObject.auto(rpcObject, methodRunner: runner);\n\n        // now lets send the response to the client if it is not null\n        // before send we must convert it to bytes using the `encode()` method\n        if (response != null) client.add(response.encode());\n      },\n    );\n  }\n}\n```\n\n```dart\nvoid client() async {\n  print('[client] connecting...');\n  final client = await Socket.connect(InternetAddress.loopbackIPv4, 8081);\n  print('[client] connected!');\n\n  // lets create controller to help send requests and responses\n  final controller = RpcController();\n\n  // lets use our controller to send requests and responses\n  controller.sendEvent.addListener(\n    // ! encode [rpcMessage] before send\n    (rpcMessage) =\u003e client.add(rpcMessage.encode()),\n  );\n\n  // lets listen for messages\n  client.listen(\n    (bytes) async {\n      // convert bytes into [RpcObject]\n      final rpcObject = RpcObject.decode(bytes);\n\n      // now lets handle the rpcObject\n      RpcObject.auto(rpcObject, controller: controller);\n    },\n  );\n\n  // now lets first request the `sum` method\n  // we will pass 3 numbers 1, 2, 3 in a list\n  // the sum will return as Future\u003cint\u003e\n  // we can handle errors by listening for [RpcError]\n  controller.request\u003cint\u003e('sum', [1, 2, 3]).then((result) {\n    print('[client] sum result: $result');\n  }).onError\u003cRpcError\u003e((error, _) {\n    print('[client] error: ${error.message}');\n  });\n\n  // ============================= //\n  // now lets call the `print` method without expecting a response\n  controller.notify(\n    'print',\n    {\n      'message': 'A message to be printed on the server side by the client',\n    },\n  );\n\n  // ============================= //\n  // now lets shutdown the server by calling the `quit` method after 5 seconds\n  // we expect no returned value\n  // so we will send a rpc notification\n  await Future.delayed(\n    const Duration(seconds: 5),\n    () =\u003e controller.notify('quit'),\n  );\n}\n```\n\n\u003c!-- \n### Server side\n\nNow lets start\n\n- First import `dart:io` and `package:general_json_rpc/general_json_rpc.dart`\n\n- Now lets create the `server` method which will simulate the server side\n\n```dart\n\nvoid server() async {\n  ...\n}\n\n```\n\nand inside lets create our simple server and bind on port `8081`\n\n```dart\nfinal server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);\nprint('[server] Server is running on port 8081');\n```\n\ncool, now let create a `MethodRunner` where we are going to define our rpc methods\n\n```dart\n\nfinal runner = MethodRunner();\n\n// now lets define our 3 methods\nrunner.register\u003cint\u003e('sum', (numbers) =\u003e numbers.reduce((a, b) =\u003e a + b));\nrunner.register\u003cvoid\u003e('print', (p) =\u003e print(p['message']));\nrunner.register\u003cvoid\u003e('quit', (_) =\u003e exit(0));\n\n```\n\ncool now we defined our 3 methods\n\nnow lets listen to the incoming connections\n\n```dart\n\nawait for(final Socket client in server) {\n  client.listen(\n    (bytes) async {\n      // 1. lets converts bytes into [RpcObject]\n      final rpcObject = RpcObject.decode(bytes);\n\n      // 2. now lets handle the coming requests\n      final result = await RpcObject.handle(\n        rpcObject,\n        onRequestAll: runner.executeRequest,\n      );\n\n      // 3. now lets encode the result and send it\n      if (result != null) client.add(result.encode());\n    },\n  );\n}\n```\n\nNow we create 3 steps to handle am incoming request\n\n1. The incoming request is a list of bytes `Uint8List`\n    we converted it to a `RpcObject` using the `decode` method\n\n2. Now lets handling the incoming request by executing the methods and send back the results, and we archived this by referencing the `runner.executeRequest` method as a `onRequestAll` callback method which will be executed when ever the request is a normal method execution or notification request.\nThe `handle` method returns a `Future` of a **nullable** `RpcObject` which the response.\n\n    \u003e Note if no returned value then no response means no returned `RpcObject` by the `handle` method\n\n3. Finally we need to check if the result is not null then we can send it back to the client\n   To send `RpcObject` you need to convert it to bytes, and this archived by using the `RpcObject.encode()` method.\n\nCool this was the server side, lets take a complete view\n\n```dart\nimport 'dart:io';\nimport 'package:general_json_rpc/general_json_rpc.dart';\n\nvoid main() {\n  server();\n}\n\nvoid server() async {\n  var server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);\n  print('[server] Server is running on port 8081');\n\n  // create MethodRunner to define the rpc methods\n  final runner = MethodRunner();\n\n  // now lets define the 3 methods\n  runner.register\u003cint\u003e('sum', (numbers) =\u003e numbers.reduce((a, b) =\u003e a + b));\n  runner.register\u003cvoid\u003e('print', (p) =\u003e print(p['message']));\n  runner.register\u003cvoid\u003e('quit', (_) =\u003e exit(0));\n\n  // now lets listen for new clients\n  await for (final Socket client in server) {\n    print('[server] new client');\n    client.listen(\n      (bytes) async {\n        // converts bytes into [RpcObject]\n        final rpcObject = RpcObject.decode(bytes);\n\n        // now lets handle different cases\n        // we will handle requests and notifications\n        // requests has a return value while notifications has not\n        // we will handle both using [onRequestAll] parameter\n        // we will use runner.executeRequest as a callback\n        // handle will return a Future of nullable [RpcObject] which is the response\n        // for the current request if it has\n        final response = await RpcObject.handle(\n          rpcObject,\n          onRequestAll: runner.executeRequest,\n        );\n\n        // now lets send the response to the client if it is not null\n        // before send we must convert it to bytes using the `encode()` method\n        if (response != null) client.add(response.encode());\n      },\n    );\n  }\n}\n```\n\n----\n\n### Client Side\n\nCool now we can start implementing the client side.\nFirst lets create the `client` method which simulates the client side\n\n```dart\nvoid client() async {\n  ...\n}\n```\n\nnow lets connect to the server\n\n```dart\n\nprint('[client] connecting...');\nfinal client = await Socket.connect(InternetAddress.loopbackIPv4, 8081);\nprint('[client] connected!');\n```\n\nCool, now lets send our requests\n\nThe first method is `sum`\n\n```dart\n// lets find out the sum of 1, 2 and 3\nfinal request = RpcRequest.create('sum', [1, 2, 3]);\n\n// now lets encode it and send to the server\nclient.add(request.encode());\n```\n\nThe next one is `print`\n\n```dart\nfinal request2 = RpcRequest.notify(\n  'print',\n  {\n    'message': 'A message to be printed on server side by client',\n  },\n);\n\nclient.add(request2.encode());\n```\n\nalso you can use the `[]` and `[]=` operators to assign params\n\n```dart\nfinal request2 = RpcRequest.notify('print', {});\nrequest2['message'] = 'A message to be printed on server side by client';\nclient.add(request2.encode());\n````\n\nNow lets see the deference between `RpcRequest.create` and `RpcRequest.notify`\n\nboth creates new instance of `RpcRequest` but `create` creates instance with a generated id while `notify` creates instance with `null` as a id value\n\n\u003e If we expect a returned value from the requested method then we need to specify an **id** for our request so later we will listen and filter the responses to find one with the same **id** to get our returned value\n\nCool, now lets see the last one which is `quit`\n\n```dart\n// We do not expect a returned value so we will use `notify`\n// no need to pass params\nfinal request3 = RpcRequest.notify('quit');\n\n// encode and send\nclient.add(request3.encode());\n```\n\n\u003e Do not forget to call `server` and `client` methods in the `main` method\n\n```dart\nvoid main() {\n  server();\n  client();\n}\n```\n\nNow lets get a complete view for what we did so far\n\n```dart\nimport 'dart:io';\nimport 'package:general_json_rpc/general_json_rpc.dart';\n\nvoid main() async {\n  server();\n  client();\n}\n\nvoid server() async {\n  var server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);\n  print('[server] Server is running on port 8081');\n\n  // create MethodRunner to define the rpc methods\n  final runner = MethodRunner();\n\n  // now lets define the 3 methods\n  runner.register\u003cint\u003e('sum', (numbers) =\u003e numbers.reduce((a, b) =\u003e a + b));\n  runner.register\u003cvoid\u003e('print', (p) =\u003e print(p['message']));\n  runner.register\u003cvoid\u003e('quit', (_) =\u003e exit(0));\n\n  // now lets listen for new clients\n  await for (final Socket client in server) {\n    print('[server] new client');\n    client.listen(\n      (bytes) async {\n        // converts bytes into [RpcObject]\n        final rpcObject = RpcObject.decode(bytes);\n\n        // now lets handle different cases\n        // we will handle requests and notifications\n        // requests has a return value while notifications has not\n        // we will handle both using [onRequestAll] parameter\n        // we will use runner.executeRequest as a callback\n        // handle will return a Future of nullable [RpcObject] which is the response\n        // for the current request if it has\n        final response = await RpcObject.handle(\n          rpcObject,\n          onRequestAll: runner.executeRequest,\n        );\n\n        // now lets send the response to the client if it is not null\n        // before send we must convert it to bytes using the `encode()` method\n        if (response != null) client.add(response.encode());\n      },\n    );\n  }\n}\n\nvoid client() async {\n  print('[client] connecting...');\n  final client = await Socket.connect(InternetAddress.loopbackIPv4, 8081);\n  print('[client], connected!');\n\n  // now lets first request the `sum` method\n  // we expect a returned value\n  // so we will send a rpc request\n  // we will pass 3 numbers 1, 2, 3 in a list\n  final request = RpcRequest.create('sum', [1, 2, 3]);\n\n  // now lets send the request to the server\n  // first encode it using the `encode()` method then send it\n  client.add(request.encode());\n\n  // ============================= //\n  // now lets call the `print` method\n  // we expect no returned value\n  // so we will send a rpc notification\n  final request2 = RpcRequest.notify('print', {});\n\n  // I created the param as an empty Map\n  // to show you how to add extra parameters to the request\n  // I am going to define key `message` and add my message to it\n  request2['message'] =\n      'A message to be printed on the server side by the client';\n\n  // now lets encode and send the notification request\n  client.add(request2.encode());\n\n  // ============================= //\n  // now lets shutdown the server by calling the `quit` method\n  // we expect no returned value\n  // so we will send a rpc notification\n  client.add(RpcRequest.notify('quit').encode());\n}\n```\n\nCool we are done, but if we run our code the `sum` method example will not work as expected because we need to listen for the server returned values on our client first.\n\n### Listen for responses\n\nFirst we need to handle responses at client side\n\n```dart\nclient.listen(\n  (bytes) {\n    final rpcObject = RpcObject.decode(bytes);\n\n    RpcObject.handle(\n      rpcObject,\n      onResponse: RpcResponseManager.global.handleResponse,\n    );\n  },\n)\n```\n\nCool now we are listening to any response and handling it on the global `RpcResponseManager` object.\n\nNow lets handle the `sum` method results\n\n```dart\nfinal request = RpcRequest.create('sum', [1, 2, 3]);\n\nclient.add(request.encode());\n\nrequest.waitForResponse().then((result) {\n    print('[client] sum result: $result');\n  }).onError\u003cRpcError\u003e((error, _) {\n    print('[client] error: ${error.message}');\n  });\n```\n\nalso you can handle it like this\n\n```dart\nfinal sum = await request.waitForResponse();\n```\n\n\u003e Do not forget we are sending a notification request with method `quit` to exit the app at the end.\n\u003e But now our app needs to wait until we get the response back so we can comment it or send it after we receive the result\n\n```dart\nrequest.waitForResponse().then((result) {\n    print('[client] sum result: $result');\n    client.add(RpcRequest.notify('quit').encode());\n  }).onError\u003cRpcError\u003e((error, _) {\n    print('[client] error: ${error.message}');\n  });\n``` --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavenchy%2Fgeneral_json_rpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavenchy%2Fgeneral_json_rpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavenchy%2Fgeneral_json_rpc/lists"}