In my previous post, I briefly mentioned FrankDux, a new project I’m working on. FrankDux is a framework for quickly building RPC microservices in Python. This is a preview of it’s functionality and subject to change.

A goal of FrankDux is to provide a means of building stateless microservices that’s as easy as working with Flask or Bottle, but also the conveniences of Cap’n Proto, of which I’m a huge fan. Here’s the classic Hello World example, using Bottle:

from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

run(host='localhost', port=8080)

Let’s take a look at a FrankDux Hello World example in Python:

from frankdux import FrankDux
from frankdux.types import String

frank = FrankDux()

@frank.register(String, returns=String)
def hello(name):
    return "Hello " + name

if __name__ == "__main__":
    frank.run()

You’ll probably notice a few things here. One of the interesting items is @frank.register(String, returns=String). Why is this here, and what does this give us? Well, it’s simple. We get typing.

When building backend servers it’s important that we know what kind of data we’re sending and receiving. People think they love schema-less systems but most of the time what they really love is flexibility to make changes. See my rant on schema-less from July 2014.

What do we do with these types? If we were just using REST over HTTP, probably not much. It’s important to keep in mind this is a micro service layer, and we don’t need to encode everything so it can be decoded by Javascript. In fact, we can do a lot more than just get and enforce typing. We can use this information for code generation, which brings me to my next point.

Developing against a service where you have to read (possibly inaccurate) documentation to figure out what’s available is a ridiculous proposition. By generating client libraries for the different languages we want to consume the service with, we can ensure that we don’t waste a ton of time with trial and error nonsense. I should note that this is not a new idea - tools like Thrift, Avro, Cap’n Proto, etc, have done this already. The different part here is the speed which it should be possible to develop new services with Python (REALLY FAST I PROMISE).

We can generate out client libraries for our target language using the frankdux command line utility (which will be installed as part of the package):

frankdux app:frank python

At this point, you’re probably thinking that working with simple Strings isn’t going to be enough to build microservices, and you’re absolutely right. We’re going to need complex objects.

from frankdux import FrankDux
from frankdux.types import Type, Int, Float, String

frank = FrankDux()

class User(Type):
    name = String()
    age = Int()

@frank.register(String, Int, returns=User)
def create_user(name, age):
    return User(name=name, age=age)

We can do more than just simple objects. We can compose classes of other classes, and support collections as well.

class Address(object):
    street = String()
    state = String()
    zip = String()
   
class User(object):
    name = String()
    addresses = Map(String, Address)

You’ll be able to compose types together to create complex RPCs. The first of which will be my own, KillrAnswers, a microservice for adding Question & Answer functionality to systems.

That’s going to wrap up the preview for now. In follow up posts I’ll be discussing ZeroMQ patterns, message encoding, complex data models, integration with other libraries, programming patterns, and deploying into production.

Please keep in mind the roadmap isn’t set in stone, so it’s possible everything I wrote above will change. I’ll be evolving the FrankDux library as my own uses of it reveal problems that need to be solved.