RPC Docs.
This is a slightly more advanced guide for those using Prim+RPC outside of JavaScript. You do not need to read this to understand how to use Prim+RPC.
While using Prim+RPC's client to generate RPC is incredibly easy and painless, there may be situations where you would like to learn how to structure a request to a Prim+RPC server. Maybe you are developing an application with Swift/Kotlin and need to connect to Prim+RPC from an ordinary HTTP client, maybe you're looking to intercept requests with a Web Worker for caching, or maybe you are just curious as to how it works.
Before you learn how to format an RPC manually, you should also know that Prim+RPC has a low-level documentation generator for which you could generate RPC snippets for popular HTTP clients using HTTPSnippet. These can be customized for your own code being used with Prim+RPC. This is useful when you have potentially hundreds of different method calls to make. Otherwise, you may just learn how to make the request yourself since it is designed to be easy to do.
While Prim+RPC only deals with the RPC portion of the request, plugins used with Prim+RPC generally follow a particular format to deliver that RPC (although they're not technically required to do so). We'll discuss this by working with typical RPCs that may be sent in Prim+RPC.
Let's look at a simple function call and compare it directly against the resulting RPC. We'll define the client and
server in the same file for easier reading. In a real-world scenario, we would use a Prim+RPC plugin but we'll use
testing plugins for example. The focus is only on the add()
function but if you'd like to test this out, you may copy
the snippet below to see how it actually runs.
The function call above, when used with Prim+RPC, would generate the following RPC request and result:
It's that simple! If you were to make this RPC manually, you wouldn't even need to include the "id" property in the request (this is optional and is used by the Prim+RPC client to sort out batched requests). Depending on how you send/receive RPC, this result may be wrapped in some other other container, like an HTTP request, but the RPC itself is contained in this JSON.
We simply gave the method name and arguments to the method then received a result. Our arguments were given as an array because we have more than one but if we had a single argument (maybe an object), then we would simply need to pass that argument without wrapping in an array. Let's say we have function like so:
When used with Prim+RPC, this would result in the following RPC:
That's about all there is to know about making a simple function call and receiving a result. However, there are situations where you may not receive a return value back. We'll cover this situation next.
Most of the time requests with Prim+RPC will return a result in its RPC contained in the .result
property of the
response. However, if your function throws an error, then this is no longer the case. When your function errors on the
server, that error is caught, serialized, and forwarded to the client where the error is recreated and thrown for the
client to handle.
Let's take our previous add()
example and make a small modification:
function add(a: number, b: number) { if (typeof a !== "number") { throw "a is not number" } if (typeof b !== "number") { throw "b is not number" } return a + b}
Given valid input, the RPC result is still the same as it was before. However, if we give an argument of a string, an error is thrown and the following result is received.
Running this code would result in the following RPC:
The error thrown on the server was serialized and sent to the client on the property .error
which was then thrown
again on the Prim+RPC client.
You also have the option of throwing an Error
object which are serialized by default using the library
serialize-error. This is the default option in Prim+RPC but can also
be disabled by setting an option in Prim+RPC handleError
to false
.
Prim+RPC can also support callbacks given as an argument to a function that you define. Since callbacks are called at a later point in time, the initial RPC is followed not just by a single return value but with multiple responses for each time the callback given is called from the server.
It's easiest to explain with an example. Let's take a look at the function below.
function typeMessage(message: string, typeLetter: (letter: string) => void) { let timeout = 0 message.split("").forEach(letter => { setTimeout(() => { typeLetter(letter) }, ++timeout * 150) })}// example usagetypeMessage("Hi!", letter => console.log(letter))
This function takes a string message and, for each letter in the message, calls typeLetter()
with a short delay
between each letter. Similar to other function calls, there is an initial RPC and a response:
We can't serialize the callback function, so instead it is replaced with a string identifier that we will keep track of when we receive a result from the server. When the server calls the callback, we can expect the server to return this identifier back to use with the arguments used on the server when it was called. Prim+RPC's client will automatically generate the callback identifier and match it with a response from the server. When using outside of JavaScript, the request and responses (typically over a WebSocket connection) need to be matched.
Note that the return value of the function is null
because the function had no return value (and undefined
can't be
sent back with the default JSON handler, because it's not a valid JSON value).
However, we're not done yet. The Prim+RPC server will send back additional messages as the callback is called from the server (tap each tab to see responses):
Each callback result includes the identifier that we sent in the request for us to match back to the request.
Up until this point, we've worked with primitive values on the function. With Prim+RPC we can override the default JSON handler and use a custom handler. It doesn't even necessarily need to be JSON.
Documentation in Progress
Prim+RPC can handle files in two different ways: by supporting files in a custom JSON-like handler or by using the default JSON handler and separating files from the RPC itself (by replacing files in a request with identifiers to the file).
Documentation in Progress
Prim+RPC can batch multiple function calls into a single request.
Documentation in Progress