← ~/blog
Systems May 2, 2026 · 8 min read

What a binary wire protocol taught me about API design

When every byte is yours to define, you start seeing REST APIs differently.

Framing: the problem HTTP hides from you

TCP gives you a stream of bytes, not messages. The first thing every protocol needs is framing — a way to know where one message ends and the next begins. For Flume I used length-prefixed frames:

+----------+----------+------------------+
| length   | type     | payload          |
| uint32   | uint8    | length - 1 bytes |
+----------+----------+------------------+

Four bytes of length, one byte of message type, then the payload. That's it. HTTP does the same job with headers and chunked encoding — you just never have to think about it until you build the layer underneath.

Versioning is day-one work

The moment a client and server can be deployed separately, you have a compatibility problem. Kafka's protocol carries an API version in every request header — I copied that, and it saved me the first time I changed the produce message layout. The REST equivalent — versioned routes, additive-only schema changes — is the same discipline wearing different clothes.

What carries over to everyday APIs

Three habits survived the trip back up the stack: never break the frame (make responses self-describing), version from the first release, and treat every field you add as a promise you'll keep forever. JSON lets you be sloppy about all three — binary protocols don't, and the constraint is a good teacher.

networking tcp protocols
← previous Raft, explained by building it next → The log at the heart of every system