Walkthrough

Setting up

To get started, you must obtain the .proto file(s) that describe the interface you want to use and add those files to your project.

Add .proto files to your project’s src/main/protobufsrc/main/protosrc/main/proto directory. See the detailed chapters on sbt, Gradle and Maven for information on picking up .proto definitions from dependencies automatically.

Then add the following configuration to your build:

sbt
// in project/plugins.sbt:
resolvers += "Akka library repository".at("https://repo.akka.io/maven")
addSbtPlugin("com.lightbend.akka.grpc" % "sbt-akka-grpc" % "2.4.1")
//
// in build.sbt:
resolvers += "Akka library repository".at("https://repo.akka.io/maven")
enablePlugins(AkkaGrpcPlugin)
Gradle
buildscript {
  repositories {
gradlePluginPortal()
maven {
  url "https://repo.akka.io/maven"
}
  }
}
plugins {
  id 'java'
  id 'application'
  id 'com.lightbend.akka.grpc.gradle' version '2.4.1'
}
repositories {
  mavenCentral()
  maven {
url "https://repo.akka.io/maven"
  }
}
Maven
<project>
  <modelVersion>4.0.0</modelVersion>
  <name>Project name</name>
  <groupId>com.example</groupId>
  <artifactId>my-grpc-app</artifactId>
  <version>0.1-SNAPSHOT</version>
  <properties>
<akka.grpc.version>2.4.1</akka.grpc.version>
<grpc.version>1.60.2</grpc.version>
<project.encoding>UTF-8</project.encoding>
  </properties>
  <repositories>
<repository>
  <id>akka-repository</id>
  <name>Akka library repository</name>
  <url>https://repo.akka.io/maven</url>
</repository>
  </repositories>
  <pluginRepositories>
<pluginRepository>
  <id>akka-repository</id>
  <name>Akka library repository</name>
  <url>https://repo.akka.io/maven</url>
</pluginRepository>
  </pluginRepositories>
  <dependencies>
<dependency>
  <groupId>com.lightbend.akka.grpc</groupId>
  <artifactId>akka-grpc-runtime_2.13</artifactId>
  <version>${akka.grpc.version}</version>
</dependency>
<!-- for loading of cert, issue #89 -->
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-testing</artifactId>
  <version>${grpc.version}</version>
</dependency>
  </dependencies>
  <build>
<plugins>
  <plugin>
    <groupId>com.lightbend.akka.grpc</groupId>
    <artifactId>akka-grpc-maven-plugin</artifactId>
    <version>${akka.grpc.version}</version>
    <!-- Hook the generate goal into the lifecycle,
         automatically tied to generate-sources -->
    <executions>
      <execution>
        <goals>
          <goal>generate</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
  </build>
</project>

For a complete overview of the configuration options see the chapter for your build tool, sbt, Gradle or Maven.

Dependencies

The Akka gRPC plugin makes your code depend on the akka-grpc-runtime library.

The table below shows direct dependencies of it and the second tab shows all libraries it depends on transitively. Be aware that the io.grpc.grpc-api library depends on Guava.

Direct dependencies
OrganizationArtifactVersion
com.google.protobufprotobuf-java3.24.0
com.thesamet.scalapbscalapb-runtime_2.130.11.15
com.typesafe.akkaakka-discovery_2.132.9.2
com.typesafe.akkaakka-http-core_2.1310.6.1
com.typesafe.akkaakka-http_2.1310.6.1
com.typesafe.akkaakka-stream_2.132.9.2
io.grpcgrpc-core1.60.2
io.grpcgrpc-netty-shaded1.60.2
io.grpcgrpc-protobuf1.60.2
org.scala-langscala-library2.13.12
Dependency tree
com.google.protobuf    protobuf-java    3.24.0
com.thesamet.scalapb    scalapb-runtime_2.13    0.11.15    Apache 2
    com.google.protobuf    protobuf-java    3.24.0
    com.thesamet.scalapb    lenses_2.13    0.11.15    Apache 2
        org.scala-lang.modules    scala-collection-compat_2.13    2.11.0    Apache-2.0
            org.scala-lang    scala-library    2.13.12    Apache-2.0
        org.scala-lang    scala-library    2.13.12    Apache-2.0
    org.scala-lang.modules    scala-collection-compat_2.13    2.11.0    Apache-2.0
        org.scala-lang    scala-library    2.13.12    Apache-2.0
    org.scala-lang    scala-library    2.13.12    Apache-2.0
com.typesafe.akka    akka-discovery_2.13    2.9.2    BUSL-1.1
    com.typesafe.akka    akka-actor_2.13    2.9.2    BUSL-1.1
        com.typesafe    config    1.4.3    Apache-2.0
        org.scala-lang.modules    scala-java8-compat_2.13    1.0.2    Apache-2.0
            org.scala-lang    scala-library    2.13.12    Apache-2.0
        org.scala-lang    scala-library    2.13.12    Apache-2.0
    org.scala-lang    scala-library    2.13.12    Apache-2.0
com.typesafe.akka    akka-http-core_2.13    10.6.1    BUSL-1.1
    com.typesafe.akka    akka-parsing_2.13    10.6.1    BUSL-1.1
        org.scala-lang    scala-library    2.13.12    Apache-2.0
    org.scala-lang    scala-library    2.13.12    Apache-2.0
com.typesafe.akka    akka-http_2.13    10.6.1    BUSL-1.1
    com.typesafe.akka    akka-http-core_2.13    10.6.1    BUSL-1.1
        com.typesafe.akka    akka-parsing_2.13    10.6.1    BUSL-1.1
            org.scala-lang    scala-library    2.13.12    Apache-2.0
        org.scala-lang    scala-library    2.13.12    Apache-2.0
    org.scala-lang    scala-library    2.13.12    Apache-2.0
com.typesafe.akka    akka-stream_2.13    2.9.2    BUSL-1.1
    com.typesafe.akka    akka-actor_2.13    2.9.2    BUSL-1.1
        com.typesafe    config    1.4.3    Apache-2.0
        org.scala-lang.modules    scala-java8-compat_2.13    1.0.2    Apache-2.0
            org.scala-lang    scala-library    2.13.12    Apache-2.0
        org.scala-lang    scala-library    2.13.12    Apache-2.0
    com.typesafe.akka    akka-protobuf-v3_2.13    2.9.2    BUSL-1.1
    org.reactivestreams    reactive-streams    1.0.4    MIT-0
    org.scala-lang    scala-library    2.13.12    Apache-2.0
io.grpc    grpc-core    1.60.2    Apache 2.0
    com.google.android    annotations    4.1.1.4    Apache 2.0
    com.google.code.gson    gson    2.10.1    Apache-2.0
    com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
    com.google.guava    guava    32.0.1-android
        com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
        com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
        com.google.guava    failureaccess    1.0.1
        com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
        com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
        org.checkerframework    checker-qual    3.33.0    The MIT License
    io.grpc    grpc-api    1.60.2    Apache 2.0
        com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
        com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
        com.google.guava    guava    32.0.1-android
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    failureaccess    1.0.1
            com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
            com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
            org.checkerframework    checker-qual    3.33.0    The MIT License
    io.grpc    grpc-context    1.60.2    Apache 2.0
        io.grpc    grpc-api    1.60.2    Apache 2.0
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    guava    32.0.1-android
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    failureaccess    1.0.1
                com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                org.checkerframework    checker-qual    3.33.0    The MIT License
    io.grpc    grpc-util    1.60.2    Apache 2.0
        com.google.guava    guava    32.0.1-android
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    failureaccess    1.0.1
            com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
            com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
            org.checkerframework    checker-qual    3.33.0    The MIT License
        io.grpc    grpc-api    1.60.2    Apache 2.0
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    guava    32.0.1-android
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    failureaccess    1.0.1
                com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                org.checkerframework    checker-qual    3.33.0    The MIT License
        org.codehaus.mojo    animal-sniffer-annotations    1.23
    io.perfmark    perfmark-api    0.26.0    Apache 2.0
    org.codehaus.mojo    animal-sniffer-annotations    1.23
io.grpc    grpc-netty-shaded    1.60.2    Apache 2.0
    com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
    com.google.guava    guava    32.0.1-android
        com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
        com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
        com.google.guava    failureaccess    1.0.1
        com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
        com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
        org.checkerframework    checker-qual    3.33.0    The MIT License
    io.grpc    grpc-core    1.60.2    Apache 2.0
        com.google.android    annotations    4.1.1.4    Apache 2.0
        com.google.code.gson    gson    2.10.1    Apache-2.0
        com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
        com.google.guava    guava    32.0.1-android
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    failureaccess    1.0.1
            com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
            com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
            org.checkerframework    checker-qual    3.33.0    The MIT License
        io.grpc    grpc-api    1.60.2    Apache 2.0
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    guava    32.0.1-android
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    failureaccess    1.0.1
                com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                org.checkerframework    checker-qual    3.33.0    The MIT License
        io.grpc    grpc-context    1.60.2    Apache 2.0
            io.grpc    grpc-api    1.60.2    Apache 2.0
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    guava    32.0.1-android
                    com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                    com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                    com.google.guava    failureaccess    1.0.1
                    com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                    com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                    org.checkerframework    checker-qual    3.33.0    The MIT License
        io.grpc    grpc-util    1.60.2    Apache 2.0
            com.google.guava    guava    32.0.1-android
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    failureaccess    1.0.1
                com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                org.checkerframework    checker-qual    3.33.0    The MIT License
            io.grpc    grpc-api    1.60.2    Apache 2.0
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    guava    32.0.1-android
                    com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                    com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                    com.google.guava    failureaccess    1.0.1
                    com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                    com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                    org.checkerframework    checker-qual    3.33.0    The MIT License
            org.codehaus.mojo    animal-sniffer-annotations    1.23
        io.perfmark    perfmark-api    0.26.0    Apache 2.0
        org.codehaus.mojo    animal-sniffer-annotations    1.23
    io.perfmark    perfmark-api    0.26.0    Apache 2.0
io.grpc    grpc-protobuf    1.60.2    Apache 2.0
    com.google.api.grpc    proto-google-common-protos    2.22.0    Apache-2.0
        com.google.protobuf    protobuf-java    3.24.0
    com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
    com.google.guava    guava    32.0.1-android
        com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
        com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
        com.google.guava    failureaccess    1.0.1
        com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
        com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
        org.checkerframework    checker-qual    3.33.0    The MIT License
    com.google.protobuf    protobuf-java    3.24.0
    io.grpc    grpc-api    1.60.2    Apache 2.0
        com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
        com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
        com.google.guava    guava    32.0.1-android
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    failureaccess    1.0.1
            com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
            com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
            org.checkerframework    checker-qual    3.33.0    The MIT License
    io.grpc    grpc-protobuf-lite    1.60.2    Apache 2.0
        com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
        com.google.guava    guava    32.0.1-android
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    failureaccess    1.0.1
            com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
            com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
            org.checkerframework    checker-qual    3.33.0    The MIT License
        io.grpc    grpc-api    1.60.2    Apache 2.0
            com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
            com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
            com.google.guava    guava    32.0.1-android
                com.google.code.findbugs    jsr305    3.0.2    The Apache Software License, Version 2.0
                com.google.errorprone    error_prone_annotations    2.20.0    Apache 2.0
                com.google.guava    failureaccess    1.0.1
                com.google.guava    listenablefuture    9999.0-empty-to-avoid-conflict-with-guava
                com.google.j2objc    j2objc-annotations    2.8    Apache License, Version 2.0
                org.checkerframework    checker-qual    3.33.0    The MIT License
org.scala-lang    scala-library    2.13.12    Apache-2.0

Generating Service Stubs

To use a service, such as the Hello World service described in the server documentation, you only need the protobuf definition (the .proto files) of the service. No additional dependencies to the server project are needed.

For example, this is the definition of a Hello World service:

sourcesyntax = "proto3";

option java_multiple_files = true;
option java_package = "example.myapp.helloworld.grpc";
option java_outer_classname = "HelloWorldProto";

package helloworld;

////////////////////////////////////// The greeting service definition.
service GreeterService {
    //////////////////////
    // Sends a greeting //
    ////////*****/////////
    //      HELLO       //
    ////////*****/////////
    rpc SayHello (HelloRequest) returns (HelloReply) {}

    // Comment spanning
    // on several lines
    rpc ItKeepsTalking (stream HelloRequest) returns (HelloReply) {}

    /*
     * C style comments
     */
    rpc ItKeepsReplying (HelloRequest) returns (stream HelloReply) {}

    /* C style comments
     * on several lines
     * with non-empty heading/trailing line */
    rpc StreamHellos (stream HelloRequest) returns (stream HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
    string name = 1;
}

// The response message containing the greetings
message HelloReply {
    string message = 1;
}

From this definition, Akka gRPC generates interfaces that look like this:

Scala
source
// Generated by Akka gRPC. DO NOT EDIT. package example.myapp.helloworld.grpc import akka.annotation.ApiMayChange import akka.grpc.AkkaGrpcGenerated /** * #services * //////////////////////////////////// The greeting service definition. */ @AkkaGrpcGenerated trait GreeterService { /** * //////////////////// * Sends a greeting // * //////&#42;****&#47;//////// * HELLO // * //////&#42;****&#47;//////// */ def sayHello(in: example.myapp.helloworld.grpc.HelloRequest): scala.concurrent.Future[example.myapp.helloworld.grpc.HelloReply] /** * Comment spanning * on several lines */ def itKeepsTalking(in: akka.stream.scaladsl.Source[example.myapp.helloworld.grpc.HelloRequest, akka.NotUsed]): scala.concurrent.Future[example.myapp.helloworld.grpc.HelloReply] /** * C style comments */ def itKeepsReplying(in: example.myapp.helloworld.grpc.HelloRequest): akka.stream.scaladsl.Source[example.myapp.helloworld.grpc.HelloReply, akka.NotUsed] /** * C style comments * on several lines * with non-empty heading/trailing line */ def streamHellos(in: akka.stream.scaladsl.Source[example.myapp.helloworld.grpc.HelloRequest, akka.NotUsed]): akka.stream.scaladsl.Source[example.myapp.helloworld.grpc.HelloReply, akka.NotUsed] } @AkkaGrpcGenerated object GreeterService extends akka.grpc.ServiceDescription { val name = "helloworld.GreeterService" val descriptor: com.google.protobuf.Descriptors.FileDescriptor = example.myapp.helloworld.grpc.HelloworldProto.javaDescriptor; object Serializers { import akka.grpc.scaladsl.ScalapbProtobufSerializer val HelloRequestSerializer = new ScalapbProtobufSerializer(example.myapp.helloworld.grpc.HelloRequest.messageCompanion) val HelloReplySerializer = new ScalapbProtobufSerializer(example.myapp.helloworld.grpc.HelloReply.messageCompanion) } @ApiMayChange @AkkaGrpcGenerated object MethodDescriptors { import akka.grpc.internal.Marshaller import io.grpc.MethodDescriptor import Serializers._ val sayHelloDescriptor: MethodDescriptor[example.myapp.helloworld.grpc.HelloRequest, example.myapp.helloworld.grpc.HelloReply] = MethodDescriptor.newBuilder() .setType( MethodDescriptor.MethodType.UNARY ) .setFullMethodName(MethodDescriptor.generateFullMethodName("helloworld.GreeterService", "SayHello")) .setRequestMarshaller(new Marshaller(HelloRequestSerializer)) .setResponseMarshaller(new Marshaller(HelloReplySerializer)) .setSampledToLocalTracing(true) .build() val itKeepsTalkingDescriptor: MethodDescriptor[example.myapp.helloworld.grpc.HelloRequest, example.myapp.helloworld.grpc.HelloReply] = MethodDescriptor.newBuilder() .setType( MethodDescriptor.MethodType.CLIENT_STREAMING ) .setFullMethodName(MethodDescriptor.generateFullMethodName("helloworld.GreeterService", "ItKeepsTalking")) .setRequestMarshaller(new Marshaller(HelloRequestSerializer)) .setResponseMarshaller(new Marshaller(HelloReplySerializer)) .setSampledToLocalTracing(true) .build() val itKeepsReplyingDescriptor: MethodDescriptor[example.myapp.helloworld.grpc.HelloRequest, example.myapp.helloworld.grpc.HelloReply] = MethodDescriptor.newBuilder() .setType( MethodDescriptor.MethodType.SERVER_STREAMING ) .setFullMethodName(MethodDescriptor.generateFullMethodName("helloworld.GreeterService", "ItKeepsReplying")) .setRequestMarshaller(new Marshaller(HelloRequestSerializer)) .setResponseMarshaller(new Marshaller(HelloReplySerializer)) .setSampledToLocalTracing(true) .build() val streamHellosDescriptor: MethodDescriptor[example.myapp.helloworld.grpc.HelloRequest, example.myapp.helloworld.grpc.HelloReply] = MethodDescriptor.newBuilder() .setType( MethodDescriptor.MethodType.BIDI_STREAMING ) .setFullMethodName(MethodDescriptor.generateFullMethodName("helloworld.GreeterService", "StreamHellos")) .setRequestMarshaller(new Marshaller(HelloRequestSerializer)) .setResponseMarshaller(new Marshaller(HelloReplySerializer)) .setSampledToLocalTracing(true) .build() } }
Java
source
// Generated by Akka gRPC. DO NOT EDIT. package example.myapp.helloworld.grpc; import akka.grpc.ProtobufSerializer; import akka.grpc.javadsl.GoogleProtobufSerializer; import akka.grpc.AkkaGrpcGenerated; /** * //////////////////////////////////// The greeting service definition. */ public interface GreeterService { /** * //////////////////// * Sends a greeting // * //////&#42;****&#47;//////// * HELLO // * //////&#42;****&#47;//////// */ java.util.concurrent.CompletionStage<example.myapp.helloworld.grpc.HelloReply> sayHello(example.myapp.helloworld.grpc.HelloRequest in); java.util.concurrent.CompletionStage<com.google.api.HttpBody> sayHelloHttp(example.myapp.helloworld.grpc.HelloRequest in); /** * Comment spanning * on several lines */ java.util.concurrent.CompletionStage<example.myapp.helloworld.grpc.HelloReply> itKeepsTalking(akka.stream.javadsl.Source<example.myapp.helloworld.grpc.HelloRequest, akka.NotUsed> in); /** * C style comments */ akka.stream.javadsl.Source<example.myapp.helloworld.grpc.HelloReply, akka.NotUsed> itKeepsReplying(example.myapp.helloworld.grpc.HelloRequest in); /** * C style comments * on several lines * with non-empty heading/trailing line */ akka.stream.javadsl.Source<example.myapp.helloworld.grpc.HelloReply, akka.NotUsed> streamHellos(akka.stream.javadsl.Source<example.myapp.helloworld.grpc.HelloRequest, akka.NotUsed> in); static String name = "helloworld.GreeterService"; static akka.grpc.ServiceDescription description = new akka.grpc.internal.ServiceDescriptionImpl(name, HelloWorldProto.getDescriptor()); @AkkaGrpcGenerated public static class Serializers { public static ProtobufSerializer<example.myapp.helloworld.grpc.HelloRequest> HelloRequestSerializer = new GoogleProtobufSerializer<>(example.myapp.helloworld.grpc.HelloRequest.parser()); public static ProtobufSerializer<example.myapp.helloworld.grpc.HelloReply> HelloReplySerializer = new GoogleProtobufSerializer<>(example.myapp.helloworld.grpc.HelloReply.parser()); public static ProtobufSerializer<com.google.api.HttpBody> google_api_HttpBodySerializer = new GoogleProtobufSerializer<>(com.google.api.HttpBody.parser()); } }

and model case classes for HelloRequest and HelloResponse.

The service interface is the same for the client and the server side. On the server side, the service implements the interface, on the client side the Akka gRPC infrastructure implements a stub that will connect to the remote service when called.

There are 4 different types of calls:

  • unary call - single request that returns a FutureCompletionStage with a single response, see sayHello in above example
  • client streaming call - Source (stream) of requests from the client that returns a FutureCompletionStage with a single response, see itKeepsTalking in above example
  • server streaming call - single request that returns a Source (stream) of responses, see itKeepsReplying in above example
  • client and server streaming call - Source (stream) of requests from the client that returns a Source (stream) of responses, see streamHellos in above example

Writing a Client Program

Let’s use these 4 calls from a client. Start by generating code from the .proto definition with:

sbt
compile
Gradle
./gradlew build
Maven
mvn akka-grpc:generate

A main program that calls the server with the GreeterService looks like this:

Scala
sourcepackage example.myapp.helloworld

import akka.{ Done, NotUsed }
import akka.actor.ActorSystem
import akka.grpc.GrpcClientSettings
import akka.stream.scaladsl.Source
import example.myapp.helloworld.grpc._

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{ Failure, Success }

object GreeterClient {
  def main(args: Array[String]): Unit = {
    // Boot akka
    implicit val sys = ActorSystem("HelloWorldClient")
    implicit val ec = sys.dispatcher

    // Configure the client by code:
    val clientSettings = GrpcClientSettings.connectToServiceAt("127.0.0.1", 8080).withTls(false)

    // Or via application.conf:
    // val clientSettings = GrpcClientSettings.fromConfig(GreeterService.name)

    // Create a client-side stub for the service
    val client: GreeterService = GreeterServiceClient(clientSettings)

    // Run examples for each of the exposed service methods.
    runSingleRequestReplyExample()
    runStreamingRequestExample()
    runStreamingReplyExample()
    runStreamingRequestReplyExample()

    sys.scheduler.scheduleWithFixedDelay(1.second, 1.second) { () => runSingleRequestReplyExample() }

    def runSingleRequestReplyExample(): Unit = {
      sys.log.info("Performing request")
      val reply = client.sayHello(HelloRequest("Alice"))
      reply.onComplete {
        case Success(msg) =>
          println(s"got single reply: $msg")
        case Failure(e) =>
          println(s"Error sayHello: $e")
      }
    }

    def runStreamingRequestExample(): Unit = {
      val requests = List("Alice", "Bob", "Peter").map(HelloRequest(_))
      val reply = client.itKeepsTalking(Source(requests))
      reply.onComplete {
        case Success(msg) =>
          println(s"got single reply for streaming requests: $msg")
        case Failure(e) =>
          println(s"Error streamingRequest: $e")
      }
    }

    def runStreamingReplyExample(): Unit = {
      val responseStream = client.itKeepsReplying(HelloRequest("Alice"))
      val done: Future[Done] =
        responseStream.runForeach(reply => println(s"got streaming reply: ${reply.message}"))

      done.onComplete {
        case Success(_) =>
          println("streamingReply done")
        case Failure(e) =>
          println(s"Error streamingReply: $e")
      }
    }

    def runStreamingRequestReplyExample(): Unit = {
      val requestStream: Source[HelloRequest, NotUsed] =
        Source
          .tick(100.millis, 1.second, "tick")
          .zipWithIndex
          .map { case (_, i) => i }
          .map(i => HelloRequest(s"Alice-$i"))
          .take(10)
          .mapMaterializedValue(_ => NotUsed)

      val responseStream: Source[HelloReply, NotUsed] = client.streamHellos(requestStream)
      val done: Future[Done] =
        responseStream.runForeach(reply => println(s"got streaming reply: ${reply.message}"))

      done.onComplete {
        case Success(_) =>
          println("streamingRequestReply done")
        case Failure(e) =>
          println(s"Error streamingRequestReply: $e")
      }
    }
  }
}
Java
sourcepackage example.myapp.helloworld;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.time.Duration;

import io.grpc.StatusRuntimeException;

import akka.Done;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.stream.SystemMaterializer;
import akka.stream.Materializer;
import akka.stream.javadsl.Source;
import akka.grpc.GrpcClientSettings;

import example.myapp.helloworld.grpc.*;

class GreeterClient {
  public static void main(String[] args) throws Exception {

    String serverHost = "127.0.0.1";
    int serverPort = 8090;

    ActorSystem system = ActorSystem.create("HelloWorldClient");
    Materializer materializer = SystemMaterializer.get(system).materializer();

    // Configure the client by code:
    GrpcClientSettings settings = GrpcClientSettings.connectToServiceAt("127.0.0.1", 8090, system).withTls(false);

    // Or via application.conf:
    // GrpcClientSettings settings = GrpcClientSettings.fromConfig(GreeterService.name, system);

    GreeterServiceClient client = null;
    try {
      client = GreeterServiceClient.create(settings, system);

      singleRequestReply(client);
      streamingRequest(client);
      streamingReply(client, materializer);
      streamingRequestReply(client, materializer);


    } catch (StatusRuntimeException e) {
      System.out.println("Status: " + e.getStatus());
    } catch (Exception e)  {
      System.out.println(e);
    } finally {
      if (client != null) client.close();
      system.terminate();
    }

  }

  private static void singleRequestReply(GreeterService client) throws Exception {
    HelloRequest request = HelloRequest.newBuilder().setName("Alice").build();
    CompletionStage<HelloReply> reply = client.sayHello(request);
    System.out.println("got single reply: " + reply.toCompletableFuture().get(5, TimeUnit.SECONDS));
  }

  private static void streamingRequest(GreeterService client) throws Exception {
    List<HelloRequest> requests = Arrays.asList("Alice", "Bob", "Peter")
        .stream().map(name -> HelloRequest.newBuilder().setName(name).build())
        .collect(Collectors.toList());
    CompletionStage<HelloReply> reply = client.itKeepsTalking(Source.from(requests));
    System.out.println("got single reply for streaming requests: " +
        reply.toCompletableFuture().get(5, TimeUnit.SECONDS));
  }

  private static void streamingReply(GreeterService client, Materializer mat) throws Exception {
    HelloRequest request = HelloRequest.newBuilder().setName("Alice").build();
    Source<HelloReply, NotUsed> responseStream = client.itKeepsReplying(request);
    CompletionStage<Done> done =
      responseStream.runForeach(reply ->
        System.out.println("got streaming reply: " + reply.getMessage()), mat);

    done.toCompletableFuture().get(60, TimeUnit.SECONDS);
  }

  private static void streamingRequestReply(GreeterService client, Materializer mat) throws Exception {
    Duration interval = Duration.ofSeconds(1);
    Source<HelloRequest, NotUsed> requestStream = Source
      .tick(interval, interval, "tick")
      .zipWithIndex()
      .map(pair -> pair.second())
      .map(i -> HelloRequest.newBuilder().setName("Alice-" + i).build())
      .take(10)
      .mapMaterializedValue(m -> NotUsed.getInstance());

    Source<HelloReply, NotUsed> responseStream = client.streamHellos(requestStream);
    CompletionStage<Done> done =
      responseStream.runForeach(reply ->
        System.out.println("got streaming reply: " + reply.getMessage()), mat);

    done.toCompletableFuture().get(60, TimeUnit.SECONDS);
  }

}

You can run the example with

sbt
runMain io.grpc.examples.helloworld.GreeterClient
Gradle
./gradlew run
Maven
mvn akka-grpc:generate compile exec:java -Dexec.mainClass=io.grpc.examples.helloworld.GreeterClient
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.