GeneralJsonRpc is a package that implements json-rpc v2.0 and its purpose is to ease invoking methods and exchange data throw network

the package is focusing on encoding and decoding json-rpc messages to and from bytes to ease sending and receiving using any protocol

A Quick Guide

In this guide you will create a server and client sides application that invokes methods throw tcp sockets

lets start

  • First on the server side we will define 3 methods sum, print, quit

    • The sum method will get numbers list and returns their sum

    • The print method will get a parameter named message and print its content on the server side

    • The quit method will end the application by executing exit(0);

import 'dart:io';
import 'package:general_json_rpc/general_json_rpc.dart';

void main() {
final server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);
  print('[server] Server is running on port 8081');

  // create MethodRunner to define the rpc methods
  final runner = MethodRunner();

  // now lets define the 3 methods
  runner.register<int>('sum', (numbers) => numbers.reduce((a, b) => a + b));
  runner.register<void>('print', (p) => print(p['message']));
  runner.register('quit', (_) {
    print('[server] Quit');

  // now lets listen for new clients
  await for (final Socket client in server) {
    print('[server] new client');
      (bytes) async {
        // converts bytes into [RpcObject]
        final rpcObject = RpcObject.decode(bytes);

        // now lets handle all cases
        final response = await, methodRunner: runner);

        // now lets send the response to the client if it is not null
        // before send we must convert it to bytes using the `encode()` method
        if (response != null) client.add(response.encode());
void client() async {
  print('[client] connecting...');
  final client = await Socket.connect(InternetAddress.loopbackIPv4, 8081);
  print('[client] connected!');

  // lets create controller to help send requests and responses
  final controller = RpcController();

  // lets use our controller to send requests and responses
    // ! encode [rpcMessage] before send
    (rpcMessage) => client.add(rpcMessage.encode()),

  // lets listen for messages
    (bytes) async {
      // convert bytes into [RpcObject]
      final rpcObject = RpcObject.decode(bytes);

      // now lets handle the rpcObject, controller: controller);

  // now lets first request the `sum` method
  // we will pass 3 numbers 1, 2, 3 in a list
  // the sum will return as Future<int>
  // we can handle errors by listening for [RpcError]
  controller.request<int>('sum', [1, 2, 3]).then((result) {
    print('[client] sum result: $result');
  }).onError<RpcError>((error, _) {
    print('[client] error: ${error.message}');

  // ============================= //
  // now lets call the `print` method without expecting a response
      'message': 'A message to be printed on the server side by the client',

  // ============================= //
  // now lets shutdown the server by calling the `quit` method after 5 seconds
  // we expect no returned value
  // so we will send a rpc notification
  await Future.delayed(
    const Duration(seconds: 5),
    () => controller.notify('quit'),