Skip to content

v0.6.0

Latest
Compare
Choose a tag to compare
@ulivz ulivz released this 04 Jun 17:40
· 5 commits to main since this release

Experimental Typed RPC Support

Starting with the 0.6.0 release, we are experimentally introducing support for Typed RPC.

When dealing with a single Port that requires RPC definition, we encounter a problem related to the programming paradigm. It's necessary to define Request and Response messages such as:

export type IpcDefinition = {
  a2b: {
    callFoo: {
      input: string;
    };
  };
  b2a: {
    callFooCallback: {
      result: string;
    };
  };
};

In the case where an RPC call needs to be encapsulated, the API might look like this:

function rpcCall(request: { input: string; }): Promise<{ result: string; }>;

Consequently, to associate a callback function, it becomes a requirement to include a CallbackId at the application layer for every RPC method:

 export type IpcDefinition = {
   a2b: {
     callFoo: {
       input: string;
+      callbackId: string;
     };
   };
   b2a: {
     callFooCallback: {
       result: string;
+      callbackId: string;
     };
   };
 };

Unrpc is provided to address this issue, enabling support for Typed RPC starting from the protocol layer:

// "parentPort" is a Port defined based on Unport in the previous example.
const parent = new Unrpc(parentPort);

// Implementing an RPC method.
parent.implement('getParentInfo', request => ({
  id: 'parent',
  from: request.user,
}));

The implementation on the child side is as follows:

// "parentPort" is a Port also defined based on Unport.
const child = new Unrpc(childPort);
const response = await child.call('getParentInfo', { user: "child" }); // => { id: "parent", from: "child" }

The types are defined as such:

import { Unport } from 'unport';

export type Definition = {
  parent2child: {
    getParentInfo__callback: {
      content: string;
    };
  };
  child2parent: {
    getParentInfo: {
      user: string;
    };
  };
};

export type ChildPort = Unport<Definition, 'child'>;
export type ParentPort = Unport<Definition, 'parent'>;

In comparison to Unport, the only new concept to grasp is that the RPC response message key must end with __callback. Other than that, no additional changes are necessary! Unrpc also offers comprehensive type inference based on this convention; for instance, you won't be able to implement an RPC method that is meant to serve as a response.

Note

You can find the full code example here: child-process-rpc.