In this post I’ll share my experiences on using Apache Thrift for developing a web service consumed by mobile and web clients, and why it didn’t quite work out as smoothly as I hoped.
I had an idea for a mobile app (Android and iOS) backed by server-side functionality. A web version could be added later. The service would be written in Java or Scala.
Hence I wanted to take a schema-first approach and clearly define and evolve the service contract in some IDL. I also liked the idea of auto-generating code from the schema into different languages/platforms to cut development time. Finally, I thought using a binary format (as opposed to e.g. JSON) would help reduce network traffic.
To provide me with further reassurance on the fact that it is suitable for mobile apps, Evernote apparently uses it.
Everything worked well enough with a Java service and an Android client. Thrift generates all the code for the “transfer objects” defined in the schema, the full client, and a service interface to be implemented with the actual functionality in the server.
Thrift actually offers a number of different protocols, transports, and servers, best documented on Wikipedia. For my purposes the obvious choices were TServlet on the server and a THttpClient on the client. Since there is more than one binary format I opted for the TCompactProtocol that is described as more efficient.
The Java client worked pretty well on Android (2.3+). One pitfalls I initially fell into is that the generated client is not thread-safe and it may error about responses “out of sequence” if you use it for multiple concurrent requests.
When I switched the server to Scala and Scrooge, I realised that the code generated by Scrooge could not be used with a TServlet. It’s intended to be used with Finagle which is another Twitter project. I eventually worked around this limitation. It’s also possible to use Thrift-generated Java code with Scala of course, it’s just not as nice.
When I got to iOS, I discovered that the Cocoa client does not support the TCompactProtocol but only the TBinaryProtocol. So I had to change the service to serve both TCompactProtocol (already used by Android) and TBinaryProtocol (for iOS).
Oddly, Thrift always sets application/x-thrift as the Content-Type no matter the protocol/format, so I had to customise servlet and client to use different values application/x-binary-thrift and application/x-compact-thrift to be able to serve both at the same time.
An additional gripe with the Cocoa support is that network calls in an iOS app need to be async (otherwise the UI freezes) but the client does not generate an async interface, requiring you to write a lot of boilerplate code involving NSOperationQueues. But it worked in the end.
Being open source you could always add/improve what is missing or lacking of course, but that would involve extra effort. And the code generator written in C++ doesn’t look particularly easy to customise. (The Scrooge one actually looks better.)
Apache Thrift offers a schema-first, code generation based RPC framework with support for many languages and platforms which conceptually is well suited for developing cross-language and cross-platform services.
However, you should be aware that Thrift is not a single serialisation format but has different protocols and transports. Although libraries for all the various different languages are included in the Thrift distribution, not all features are supported by all libraries, and individual libraries are of varying quality.
Therefore, you may want to check beforehand if the combination of protocol, transport, server, and languages you’re interested in works as expected.