Serving gRPC from Lagom

To be able to serve gRPC from a Lagom application you must enable Play HTTP/2 Support with HTTPS and the ALPN agent.

After adding Akka gRPC sbt plugin you need to enable the Play server side code generator in build.sbt:

Scala
akkaGrpcExtraGenerators += play.grpc.gen.scaladsl.PlayScalaServerCodeGenerator
Java
akkaGrpcExtraGenerators += play.grpc.gen.javadsl.PlayJavaServerCodeGenerator

The plugin will look for .proto service descriptors in src/main/protobuf and output an abstract class per service that you then implement, so for example for the following protobuf descriptor:

Scala
sourcesyntax = "proto3";

option java_multiple_files = true;
option java_package = "com.lightbend.lagom.scaladsl.grpc.interop";
option java_outer_classname = "HelloWorldProto";

package helloworld;

service GreeterService {
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}
Java
sourcesyntax = "proto3";

option java_multiple_files = true;
option java_package = "com.lightbend.lagom.javadsl.grpc.interop";
option java_outer_classname = "HelloWorldProto";

package helloworld;

service GreeterService {
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

You will get an abstract class named com.lightbend.lagom.scaladsl.grpc.interop.AbstractGreeterServiceRouter com.lightbend.lagom.javadsl.grpc.interop.AbstractGreeterServiceRouter. Create a concrete subclass implementing this wherever you see fit in your project, let’s say com.lightbend.lagom.scaladsl.grpc.interop.test.HelloGrpcServiceImplcom.lightbend.lagom.javadsl.grpc.interop.test.api.HelloGrpcServiceImpl like so:

Scala
sourcepackage com.lightbend.lagom.scaladsl.grpc.interop.test

import scala.concurrent.Future

import akka.actor.ActorSystem
import com.lightbend.lagom.scaladsl.grpc.interop.helloworld.AbstractGreeterServiceRouter
import com.lightbend.lagom.scaladsl.grpc.interop.helloworld.HelloReply
import com.lightbend.lagom.scaladsl.grpc.interop.helloworld.HelloRequest

class HelloGrpcServiceImpl(sys: ActorSystem) extends AbstractGreeterServiceRouter(sys) {
  override def sayHello(in: HelloRequest): Future[HelloReply] =
    Future.successful(HelloReply(s"Hi ${in.name}! (gRPC)"))
}
Java
sourcepackage com.lightbend.lagom.javadsl.grpc.interop.test.api;

import akka.actor.ActorSystem;
import com.lightbend.lagom.javadsl.grpc.interop.AbstractGreeterServiceRouter;
import com.lightbend.lagom.javadsl.grpc.interop.HelloReply;
import com.lightbend.lagom.javadsl.grpc.interop.HelloRequest;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Singleton
public class HelloGrpcServiceImpl extends AbstractGreeterServiceRouter {

  @Inject
  public HelloGrpcServiceImpl(ActorSystem sys) {
    super(sys);
  }

  @Override
  public CompletionStage<HelloReply> sayHello(HelloRequest in) {
    HelloReply reply = HelloReply.newBuilder().setMessage("Hi " + in.getName() + " (gRPC)").build();
    return CompletableFuture.completedFuture(reply);
  }
}

And then, you need to bind the new additional router in your project.

In Scala, you use additionalRouter method when creating your lagomServer instance:

Scala
source// Bind the service that this server provides
override lazy val lagomServer =
  serverFor[HelloService](wire[HelloServiceImpl])
    .additionalRouter(wire[HelloGrpcServiceImpl])

In Java, you need to bind the service with the additional router:

Java
sourceimport com.google.inject.AbstractModule;
import com.lightbend.lagom.javadsl.server.ServiceGuiceSupport;
import com.lightbend.lagom.javadsl.grpc.interop.test.api.HelloGrpcServiceImpl;
import com.lightbend.lagom.javadsl.grpc.interop.test.HelloServiceImpl;
import com.lightbend.lagom.javadsl.grpc.interop.test.api.api.HelloService;

public class HelloModule extends AbstractModule implements ServiceGuiceSupport {
  @Override
  protected void configure() {
    bindService(
        // bind the lagom service
        HelloService.class,
        HelloServiceImpl.class,
        // include additional routers (in this case a gRPC router)
        additionalRouter(HelloGrpcServiceImpl.class));
  }
}

And finally enable this module in your application.conf file:

Java
sourceplay.modules.enabled += HelloModule

A gRPC client can now connect to the server and call the provided services.

Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.