Server Reflection
This feature is experimental (Issue #850).
It implements version v1alpha of the upstream standard, so we might expect subsequent versions of the service to emerge. Also, the Java/Scala API’s to enable this feature may still change in further versions of Akka gRPC, and future versions of this feature may not work with services generated with older versions of Akka gRPC.
There may be missing features and bugs in the current implementation. If you encounter any, you are welcome to share a reproducer in our issue tracker.
Server Reflection is a gRPC feature that allows ‘dynamic’ clients, such as command-line tools for debugging, to discover the protocol used by a gRPC server at run time. They can then use this metadata to implement things like completion and sending arbitrary commands.
This is achieved by providing a gRPC service that provides endpoints that can be used to query this information.
Providing
The generated service handler includes a convenience method to create an Akka HTTP handler with your service together with Server Reflection:
- Scala
-
source
import akka.http.scaladsl._ import akka.http.scaladsl.model._ import akka.grpc.scaladsl.ServiceHandler import akka.grpc.scaladsl.ServerReflection import example.myapp.helloworld.grpc._ // Create service handler with a fallback to a Server Reflection handler. // `.withServerReflection` is a convenience method that contacts a partial // function of the provided service with a reflection handler for that // same service. val greeter: HttpRequest => Future[HttpResponse] = GreeterServiceHandler.withServerReflection(new GreeterServiceImpl()) // Bind service handler servers to localhost:8080 val binding = Http().bindAndHandleAsync( greeter, interface = "127.0.0.1", port = 8080, connectionContext = HttpConnectionContext())
- Java
-
source
import java.util.Arrays; import akka.grpc.javadsl.ServiceHandler; import akka.grpc.javadsl.ServerReflection; import akka.http.javadsl.*; import akka.http.javadsl.model.*; import example.myapp.helloworld.grpc.*; // Instantiate implementation GreeterService impl = new GreeterServiceImpl(); // Bind service handler servers to localhost:8080 return Http.get(sys) .newServerAt("127.0.0.1", 8080) .bind(GreeterServiceHandlerFactory.createWithServerReflection(impl, sys));
For more advanced setups you will have to combine your partial handler with the ServerReflection
handler explicitly.
For example, if you need to combine multiple services, or if you want to use an overload of the service factory methods. In these cases, the reflection service can be generated via ServerReflection
and manually concatenated as described in the walkthrough section on serving multiple services:
- Scala
-
source
// Create service handlers val greeterPartial: PartialFunction[HttpRequest, Future[HttpResponse]] = GreeterServiceHandler.partial(new GreeterServiceImpl(), "greeting-prefix") val echoPartial: PartialFunction[HttpRequest, Future[HttpResponse]] = EchoServiceHandler.partial(new EchoServiceImpl()) // Create the reflection handler for multiple services val reflection = ServerReflection.partial(List(GreeterService, EchoService)) // Concatenate the partial functions into a single handler val handler = ServiceHandler.concatOrNotFound( greeterPartial, echoPartial, reflection),
- Java
-
source
// Create service handlers Function<HttpRequest, CompletionStage<HttpResponse>> greetingPartial = GreeterServiceHandlerFactory.create(new GreeterServiceImpl(), "greeting-prefix", sys); Function<HttpRequest, CompletionStage<HttpResponse>> echoPartial = EchoServiceHandlerFactory.create(new EchoServiceImpl(), sys); // Create the reflection handler for multiple services Function<HttpRequest, CompletionStage<HttpResponse>> reflectionPartial = ServerReflection.create(Arrays.asList(GreeterService.description, EchoService.description), sys); // Concatenate the partial functions into a single handler ServiceHandler.concatOrNotFound( greetingPartial, echoPartial, reflectionPartial);
Consuming
The Server Reflection endpoint exposed above can be used for example to consume the service with grpc_cli:
$ ./bins/opt/grpc_cli call localhost:8080 helloworld.GreeterService.SayHello "name:\"foo\""
connecting to localhost:8080
Received initial metadata from server:
date : Wed, 08 Jan 2020 16:57:56 GMT
server : akka-http/10.1.10
message: "Hello, foo"
Received trailing metadata from server:
date : Wed, 08 Jan 2020 16:57:56 GMT
Rpc succeeded with OK status