Jan 10, 2018

Adapting a gRPC service to REST with ScalaPB Gateway

Now that we have seen a Scala gRPC service and a Scala RESTful service it's only natural to wonder if there is any middle ground. You want to have a nice and performant backend but you could also  have a lot of RESTful legacy code or be really into curl. Your wish is my command.

The first piece of the puzzle is the fact that GOOG has a standard for mapping REST APIs onto protobuf declarations. With no hacks or any hard thinking you can augment your existing proto files to be REST-friendly.

The second piece is making use of such a mapping. Apparently there is a Go implementation of what is known as gRPC Gateway. It can work with any gRPC service and so could be used with the ones implemented in Scala. But there is another, arguably more appealing option. The ScalaPB library we met before can generate a Scala RESTful gateway too. I guess it's not as well tested or supported but then again there is not that much code behind it to prevent it from serious use.

So I went ahead and updated my two-service gRPC example to support ScalaPB REST Gateway generation. It intentionally borrows a lot from the pure gRPC example so that the difference can be easily seen by comparing files. Technically, you still need exactly the same gRPC service implementation as before. The proto files are almost the same.

There are two new objects. To begin with we need a new abstraction to wire together the generated Gateway code. It's essentially a gRPC client with hooks to plug the RESTful stuff into it. The other is just a typical HTTP client. I followed the path of least resistance and used Jackson for JSON marshaling and commons-http for sending requests. There is a little wiring but in general the code speaks for itself.

What I learned from this exercise is that making gRPC co-exist with REST is easy. I am not sure if running a Gateway locally for each service instance is a better idea than creating a single API Gateway service to front the rest of the backend.

As a parting note, I am surprised there is no other IDL for describing RESTful services for the purpose of code generation. With a standard AST and parser library it would be quite strait forward to generate REST endpoints for any popular service framework. It's equally surprising that the Akka team does not have a generator for akka-http endpoint from protobuf declarations. It looks like such a natural step for them and the ScalaPB project even has the foundation in place.

Jan 9, 2018

Asynchronous RPC server with Akka HTTP

At work my team maintains a number of RESTful services. The good news is that they are implemented with akka-http which makes things tolerable. The bad news is that it's all about REST and JSON. So we are having a lively debate about a possible migration to something more like gRPC.

Personally, I am not a fan of non-binary protocols and data formats. At least partially it is related to my experience in building analytics systems where any query routinely requires a lot of data. Yes, for the time being you have to use REST/JSON to communicate between the browser and your API Gateway. But using the same approach to make your backend services talk to each other never made sense to me. I am really looking forward to the day when WASM/HTTP2&Co finally make front end development great again.

In the mean time I would like to see if I can gather enough evidence in favor of my position. So in the spirit of my recent gRPC experiment I am going to implement basically the same API with REST. As a bonus, I want to mention a couple of observations I made using akka-http. As usual, the code is on github. I continue the tradition of implementing a service with two endpoints. I even mostly follow the same code structure as before with gRPC.


The picture above sketches high-level interactions. There are a few noteworthy Akka-related details inside but nobody will be surprised by another RESTful service implementation.
  • TestServiceA - is where the actual logic would be. It also hosts a trait and case classes which would be generated from a protobuf file in case of gRPC
  • HttpEndpointA - an actual HTTP endpoint that plugs service logic into HTTP network endpoint. A good example of Akka HTTP expressiveness.
  • AkkaHttpServer - the service implementation entry point. In typical Scala fashion it directly implements the main method and performs basic Akka dependency wiring. It is also responsible for binding request handlers to the underlying HTTP server.
  • Http - technically an object in a high-level Akka API it represents the usual functionality of request/response-style interactions over HTTP 
  • AkkaHttpClient - not shown; wraps akka-http-based client logic. I spent some time getting it right because client-side examples are harder to find. In particular it illustrates how to use Spray JSON marshaller. But it could be any HTTP client capable of sending a POST request with a JSON body. 
If you are curious enough to look at the code I would like to highlight a few details useful in real life. Not all of them are prominent enough in usual examples. The HttpEndpointA class would be a good illustration of most of them.
  • ExceptionHandler - you can configure a handler for exceptions uncaught otherwise. It is the last line of defense against unexpected problems. 
  • RejectionHandler - such a handler is very useful if you want to explicitly deal with invalid requests (e.g. garbled JSON or more likely a JSON body representing a request to some other service)
  • request timeout - even though Akka has a default global property ("akka.http.server.request-timeout") you could configure it explicitly for a service that is expected to take an unusually long time 
  • implicit JSON (de)serialization with Spray - it's very convenient to use but rather puzzling initially to configure. In addition to the marshaller object holding implicit vals notice how the "import ServiceAJsonMarshaller" statement makes it usable by "as" and "complete" directives
  • composing multiple Routes - different styles are possible here; if there were another URL to support in this endpoint we could (a) declare another "def process2: Route" and then compose the two with "process ~ process2" using another somewhat cryptic Akka directive
On the client side there are a few more details to mention. My first reaction was that Akka HTTP client code looks somehow less straitforward than what one would see with, say, commons-http. Any HTTP client would work for this example but I wanted to see one with akka-http to better grok the API.
  • JSON marshalling with Spray was a puzzle again. It was not clear to me from the official documentation but googling helped.
  • Somewhat unusually, the client requires the same ActorSystem and Materializer infrastructure as the server. 
My conclusion is that if circumstances force me to implement anything RESTful I will reach for Akka HTTP first. But in comparison with real RPC it's more work to produce less safe code. But that's a topic for another day.

Jan 1, 2018

gRPC in Scala with ScalaPB

Curiously enough my old post on gRPC still gets disproportionately many hits. Now that I work with Scala full time I was curious to see how my old Java example would compare with a Scala version. Spoiler alert: I don't have that much new to report. Other people covered it better before. This post probably makes more sense as a head-to-head comparison between Java and Scala versions.

From what I see Scala people tend to avoid Java libraries. I am skeptical it's a good idea especially around networking and concurrency where the Java ecosystem is at its best. But I am still learning and have no strong opinions developed yet. After all, last time I used Java j.u.c Futures, Guava Futures, and CompletableFutures were still all in the game.

In case of gRPC the unofficial Scala code generator is known as ScalaPB. Once you configure it in your SBT project it feels as natural as the official Java version. The good news is that the generated code operates in terms of Scala Futures and so feels idiomatic. But you still need to initialize the gRPC foundation and that part looks almost the same as in Java.

As before, the goal is to support two different service endpoints on the same server and to have fully asynchronous client and server implementations. As we concentrate on the request/response approach we completely ignore the question of streaming. gRPC bootstrap code is so simple that I could not find enough of it to extract anything truly generic. So even though I notionally have a server and a client they just wrap initialization logic and might be unnecessary.

There are a couple technicalities I would like to highlight:
  • I had to google and experiment to find out how to configure ScalaPB for a multi-module project and a non-default proto file directory
  • even though your actual logic is all about Futures and so requires ExecutionContexts, it's easier to start with an Executor to name threads and configure underlying thread pools and then wrap it into a context
  • I can think of a few slightly different ways to propagate ExecutionContexts; implicit vals are idiomatic but seem to be less readable despite saving a little typing
All in all, using ScalaPB feels a little more idiomatic but not that different from how it's done in Java.