Differentiations

Schema definition layer

The first and biggest difference between this and all other (except for one) RPC layers is the schema definition layer. Schema definitions are in Capnproto, which, among other things, has support for interfaces as first-class citizens. This means interfaces can be passed around, sent over the wire, etc.


interface AddressBook {
  find @0 (name :Text) -> Person;
}

struct Person {
  name @0 :Text;
  ...
  interface UpdatePerson {
    update @0 Person -> ();
    delete @1 () -> ();
  }
  updater @1 :UpdatePerson;
}

The great benefit of this ability in the schema means we can express more clearly what we want to do. In the above schema, you can find a person by name, and then update them or even delete them by calling person.updater.delete().

In an API that does not have this, you go through this circuitous route of getting the ID of the person and then calling the appropriate method on the AddressBook and pass in that ID. While that is possible, and essentially what REST APIs have at their foundation, it can get convoluted as there are many ways to get the ID of a Person and many uses of that ID.

With the interface passed with the struct, you get clear information about what is even possible with the record you received. In fact, you could even return a read-only version of a record that has no interfaces that allow writing, but only reading, or limit what they can read by not providing interfaces to retrieve the phone number, address, or any other sensitive data.

This works in this schema because by passing an interface to a client, permission to use that interface is implicitly granted. No further authentication is necessary and the client can use any interfaces received.

From pycapnp

While the schema definition layer is exactly the same as with pycapnp, cara is agnostic as to the serialization and networking layer. This allows you to use whatever layers your project already uses, as well as experiment with others. The driving force behind cara was to use the best of every layer and not let any one layer dictate the others. With cara, you can do anything you wish.

The one thing it doesn't support at the moment is zero-copy (de)serialization that pycapnp does. However, if your application needs zero-copy for speed, then you're not likely to be using Python anyway. However, zeromq and msgpack both have zero-copy solutions it their C++ implementations, getting you pretty close to capnp's claimed 0us times, without enforcing its ideas on how you allocate, set, and get your data.