Techdozo
  • Microservices
    • All
    • GraphQL
    • gRPC
    • Spring Boot
    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    Distributed transaction in microservices using Saga

    Distributed Transactions in Microservices: implementing Saga with Temporal

    Temporal Workflow Orchestration

    Workflow Orchestration with Temporal and Spring Boot

    GraphQL Directive

    GraphQL Directive

    Spring for GraphQL mutation

    Spring for GraphQL: Mutation

  • Spring Boot
    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful API Gateway with gRPC

    RESTful API Gateway with gRPC

  • gRPC
    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    gRPC Interceptor: unary interceptor with code example

    gRPC Interceptor: unary interceptor with code example

    gRPC: synchronous and asynchronous Server streaming RPC

    gRPC: synchronous and asynchronous Server streaming RPC

    Photo by Ramón Salinero on Unsplash

    gRPC: synchronous and asynchronous unary RPC in Java

    Microservices inter-process communication using gRPC

    gRPC for microservices communication

  • GraphQL
    GraphQL Directive

    GraphQL Directive

    Spring for GraphQL mutation

    Spring for GraphQL: Mutation

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring GraphQL with @Controller, @SchemaMapping and @QueryMapping

    Spring for GraphQL : @SchemaMapping and @QueryMapping

    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

  • Kubernetes
    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Components of Kubernetes Architecture

    Components of Kubernetes Architecture

    Helm Chart: quick start your app deployment on Kubernetes

    Helm Chart: quick start your app deployment on Kubernetes

    gRPC load balancing on Kubernetes (using Headless Service)

    gRPC load balancing on Kubernetes (using Headless Service)

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

  • Java
    Java Streams: Stream Operation with Examples

    Java Streams: Stream Operation with Examples

    Java Streams: stream creation with examples

    Java Streams: stream creation with examples

    Garbage Collection

    Super Fast Garbage Collectors in Java

    Calculus

    Functional Programming in Java

No Result
View All Result
  • Login
  • Microservices
    • All
    • GraphQL
    • gRPC
    • Spring Boot
    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    Distributed transaction in microservices using Saga

    Distributed Transactions in Microservices: implementing Saga with Temporal

    Temporal Workflow Orchestration

    Workflow Orchestration with Temporal and Spring Boot

    GraphQL Directive

    GraphQL Directive

    Spring for GraphQL mutation

    Spring for GraphQL: Mutation

  • Spring Boot
    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful API Gateway with gRPC

    RESTful API Gateway with gRPC

  • gRPC
    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    gRPC Interceptor: unary interceptor with code example

    gRPC Interceptor: unary interceptor with code example

    gRPC: synchronous and asynchronous Server streaming RPC

    gRPC: synchronous and asynchronous Server streaming RPC

    Photo by Ramón Salinero on Unsplash

    gRPC: synchronous and asynchronous unary RPC in Java

    Microservices inter-process communication using gRPC

    gRPC for microservices communication

  • GraphQL
    GraphQL Directive

    GraphQL Directive

    Spring for GraphQL mutation

    Spring for GraphQL: Mutation

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring GraphQL with @Controller, @SchemaMapping and @QueryMapping

    Spring for GraphQL : @SchemaMapping and @QueryMapping

    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

  • Kubernetes
    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Components of Kubernetes Architecture

    Components of Kubernetes Architecture

    Helm Chart: quick start your app deployment on Kubernetes

    Helm Chart: quick start your app deployment on Kubernetes

    gRPC load balancing on Kubernetes (using Headless Service)

    gRPC load balancing on Kubernetes (using Headless Service)

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

  • Java
    Java Streams: Stream Operation with Examples

    Java Streams: Stream Operation with Examples

    Java Streams: stream creation with examples

    Java Streams: stream creation with examples

    Garbage Collection

    Super Fast Garbage Collectors in Java

    Calculus

    Functional Programming in Java

No Result
View All Result
Techdozo
No Result
View All Result
Home Microservices gRPC

gRPC Interceptor: unary interceptor with code example

Pankaj by Pankaj
April 30, 2022
in gRPC, Microservices
Reading Time: 14 mins read
0
A A
0
gRPC Interceptor: unary interceptor with code example
0
SHARES
7.9k
VIEWS
Share on FacebookShare on TwitterShare on Linkedin

Similar to many popular frameworks, gRPC has the concept of an interceptor. Conceptually, it’s very similar to the middleware/interceptor found in other frameworks, for example, Node JS middleware, Spring Boot interceptor, Django middleware, etc. The gRPC interceptor allows us to intercept gRPC remote procedure calls (RPC) and add code to handle the crosscutting concerns.

In this article, we will understand the gRPC unary interceptor with code examples in Java. This blog assumes that you have a general understanding of gRPC, but if you are new to gRPC, you can check the following articles.

gRPC for microservices communication

gRPC: synchronous and asynchronous unary RPC

gRPC: synchronous and asynchronous Server streaming RPC

Let’s get started.

In this article
  • What are gRPC Interceptors?
  • Client unary interceptor
    • Intercepting request
    • Intercepting response
    • Configuring client interceptor
  • Server unary interceptor
    • Intercepting request
    • Intercepting response
    • Configuring server interceptor
  • Context propagation in gRPC
  • ThreadLocal variable in the interceptor
  • Code Example
  • Summary

What are gRPC Interceptors?

As the name suggests, the gRPC interceptor allows you to intercept RPC. By using an interceptor, you can write reusable code for cross-cutting concerns such as logging, authentication, metrics, etc.

In gRPC, you can intercept RPC at both the client and server. Also, gRPC supports intercepting both unary and streaming RPC.

There can be many use cases for a gRPC interceptor, such as:

  • Tracing: passing tracing information from the client application to the server.
  • Logging: logging API calls in both client and server.
  • Auth token: passing authentication information, for example, JWT, from client to server.
  • Authentication/Authorization: validating authentication tokens or implementing authorization.
  • Adding contextual information to the metadata.
  • Logging, Metrics, etc.

Client unary interceptor

Client unary interceptors are executed on the client side when a unary request is made to the server. As you may know, in the unary request, the client sends a single request and receives a single response. To define a unary client interceptor, you need to implement ClientInterceptor interface and implement interceptCall method. As you have access to the metadata object, you can add arbitrary information, such as traceId, authentication token, etc., to the metadata. The metadata object is propagated to the server, along with the request object, in the RPC call.

You can chain as many interceptors as you want. The below diagram shows how the client-side unary interceptor works.

Intercepting request

The below code shows an example of a client request interceptor, where we modify the metadata object to include the caller’s JWT token.

In a Spring-based web application, this client call can be part of a web API call, and the user token can be stored in the SecurityContext. Here, UserContext simulates SecurityContext behaviour.


public class GrpcClientRequestInterceptor implements ClientInterceptor {

  public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      final MethodDescriptor<ReqT, RespT> methodDescriptor,
      final CallOptions callOptions,
      final Channel channel) {

    return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
        channel.newCall(methodDescriptor, callOptions)) {

      @Override
      public void start(ClientCall.Listener<RespT> responseListener, Metadata headers) {
        var userToken = UserContext.getUserContext().getUserToken();
        log.info("Setting userToken in header");
        headers.put(Metadata.Key.of("JWT", Metadata.ASCII_STRING_MARSHALLER), userToken);
        super.start(responseListener, headers);
      }
    };
  }
}

Dissecting GrpcClientRequestInterceptor implementation:

  • The GrpcClientRequestInterceptor implements the interface ClientInterceptor and provides the implementation of the interceptCall method.
  • The interceptCall method implementation expects a ClientCall as return type.
  • We create a new ClientCall object as ForwardingClientCall.SimpleForwardingClientCall, by passing delegate as channel.newCall(methodDescriptor, callOptions) the constructor argument.
  • We override start method and add custom logic, and then call super.start(..).

Intercepting response

If needed, you can intercept the response from the server before the client application processes it. The below code shows an example of intercepting the server response on the client interceptor.


public class GrpcClientResponseInterceptor implements ClientInterceptor {

  public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      final MethodDescriptor<ReqT, RespT> methodDescriptor,
      final CallOptions callOptions,
      final Channel channel) {

    return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
        channel.newCall(methodDescriptor, callOptions)) {

      @Override
      public void start(Listener<RespT> responseListener, Metadata headers) {
        super.start(
            new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(
                responseListener) {

              @Override
              public void onMessage(RespT message) {
                log.debug("Received response from Server: {}", message);
                super.onMessage(message);
              }
            },
            headers);
      }
    };
  }
}

This code is similar to the above, except we wrap responseListener as new ForwardingClientCallListener.SimpleForwardingClientCallListener(responseListener) and override onMessage(RespT message) method.

Configuring client interceptor

You can associate ClientInterceptors with the channel as:


 var managedChannel =
    ManagedChannelBuilder.forAddress(host, port)
        .intercept(new GrpcClientResponseInterceptor(), new GrpcClientRequestInterceptor())
        .usePlaintext()
        .build();


The interceptors run in the reverse order in which they are added.

Server unary interceptor

Server unary interceptors are executed on the server side when a unary request is received from the client. As shown in the below diagram, you can intercept both requests to the server and responses sent from the server.

Like client interceptors, you can write different interceptors to solve different concerns and chain them together. The following diagram shows how the server-side unary interceptor works.

Intercepting request

To define a server interceptor, you need to implement the ServerInterceptor interface and provide an implementation of interceptCall method.

The below code shows an example of a server request interceptor, which authenticates a service call by validating the JWT token passed in the metadata object from the client call.


public class GrpcServerRequestInterceptor implements ServerInterceptor {

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> next) {

    log.info("Validating user token");
    var userToken = metadata.get(Metadata.Key.of("JWT", Metadata.ASCII_STRING_MARSHALLER));
    validateUserToken(userToken);
    return next.startCall(serverCall, metadata);
  }

  private void validateUserToken(String userToken) {
    // Logic to validate token
  }
}

Intercepting response

Similar to the client interceptor, you can intercept a response from the server before it’s sent back to the client. The below code shows an example of a server response interceptor.


public class GrpcServerResponseInterceptor implements ServerInterceptor {

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> next) {

    return next.startCall(
        new ForwardingServerCall.SimpleForwardingServerCall<>(serverCall) {
          @Override
          public void sendMessage(RespT message) {
            log.info("Message being sent to client : " + message);
            super.sendMessage(message);
          }
        },
        metadata);
  }
}

To get access to the response object, you can wrap the serverCall object with ForwardingServerCall.SimpleForwardingServerCall and override sendMessage method.

Configuring server interceptor

You can associate the server interceptor with the gRPC services as:


Server server =
    ServerBuilder.forPort(port)
        .addService(
            ServerInterceptors.intercept(
                productService,
                new GrpcServerResponseInterceptor(),
                new GrpcServerRequestInterceptor()))
        .build();

Context propagation in gRPC

Distributed tracing is one of the main pillars of microservices observability. One of the common patterns followed in the microservices architecture is to log traceId with every log so that end-to-end request calls can be traced. In other words, you can filter the complete log associated with a particular request provided your application does structure logging and stores logs in a central storage solution that provides query capabilities, for example, Elastic search, Stackdriver, etc. . In the java based web applications, for example, Spring Boot application, this is typically done by storing traceId in MDC, which is nothing but a ThreadLocal variable.

If you plan to use the ThreadLocal variable in the interceptor, then it’ll not work. This is because the default transport protocol of gRPC is based on Netty, an asynchronous, non-blocking I/O web server. For that reason, dispatch/callback from the interceptor can happen in different threads.

If you need to propagate context in gRPC, then you can use gRPC context. A context propagation mechanism allows you to carry scoped values across API boundaries and between threads. Examples of states propagated via context include:

  • Security principals and credentials.
  • Local and distributed tracing information.

ThreadLocal variable in the interceptor

As mentioned above, storing the ThreadLocal variable in the interceptor does not work. But if you can’t use gRPC Context, and you need to store value in the ThreadLocal variable, then you can achieve that by overriding each callback of the listner as shown below.


public class GrpcMDCInterceptor implements ServerInterceptor {

  private static final String TRACE_ID = "traceId";

  @Override
  public <R, S> ServerCall.Listener<R> interceptCall(
      ServerCall<R, S> serverCall, Metadata metadata, ServerCallHandler<R, S> next) {

    log.info("Setting user context, metadata {}", metadata);

    var traceId = metadata.get(Metadata.Key.of("traceId", Metadata.ASCII_STRING_MARSHALLER));

    MDC.put(TRACE_ID, traceId);

    try {
      return new WrappingListener<>(next.startCall(serverCall, metadata), traceId);
    } finally {
      MDC.clear();
    }
  }

  private static class WrappingListener<R>
      extends ForwardingServerCallListener.SimpleForwardingServerCallListener<R> {
    private final String traceId;

    public WrappingListener(ServerCall.Listener<R> delegate, String traceId) {
      super(delegate);
      this.traceId = traceId;
    }

    @Override
    public void onMessage(R message) {
      MDC.put(TRACE_ID, traceId);
      try {
        super.onMessage(message);
      } finally {
        MDC.clear();
      }
    }

    @Override
    public void onHalfClose() {
      MDC.put(TRACE_ID, traceId);
      try {
        super.onHalfClose();
      } finally {
        MDC.clear();
      }
    }

    @Override
    public void onCancel() {
      MDC.put(TRACE_ID, traceId);
      try {
        super.onCancel();
      } finally {
        MDC.clear();
      }
    }

    @Override
    public void onComplete() {
      MDC.put(TRACE_ID, traceId);
      try {
        super.onComplete();
      } finally {
        MDC.clear();
      }
    }

    @Override
    public void onReady() {
      MDC.put(TRACE_ID, traceId);
      try {
        super.onReady();
      } finally {
        MDC.clear();
      }
    }
  }
}

Code Example

The working code example of this article is listed on GitHub  . To run the example, clone the repository, and import grpc-unary-rpc as a project in your favourite IDE as a Gradle project.

To build the project and generate client and server stubs, run the command .\gradlew clean build. You can start the gRPC server in IDE by running the main method of the class GrpcServer. The gRPC server runs on localhost:3000.

You can find the client interceptor code in the package dev.techdozo.client.interceptor in the grpc-client module and the server interceptor code in the package dev.techdozo.product.interceptor in the grpc-server module.

Summary

The gRPC interceptor allows us to intercept gRPC remote procedure calls (RPC) and add code to handle the crosscutting concerns. A gRPC interceptor can be of type client and server. gRPC supports interceptors for both unary and streaming RPC.

Typical use cases for a gRPC interceptor are:

  • Tracing: passing tracing information from the client application to the server.
  • Logging: logging API calls in both client and server.
  • Auth token: passing authentication information, for example, JWT from client to server.
  • Authentication/Authorization: validating authentication tokens or implementing authorization.
  • Adding contextual information to the metadata.
  • Logging metrics, etc.
Previous Post

gRPC: synchronous and asynchronous Server streaming RPC

Next Post

Getting started with Spring Boot GraphQL service

Pankaj

Pankaj

Software Architect @ Schlumberger ``` Cloud | Microservices | Programming | Kubernetes | Architecture | Machine Learning | Java | Python ```

Related Posts

gRPC Bidirectional Streaming with Code Example
gRPC

gRPC Bidirectional Streaming with Code Example

February 17, 2023
gRPC Client Streaming
gRPC

gRPC Client Streaming

January 20, 2023
Distributed transaction in microservices using Saga
Microservices

Distributed Transactions in Microservices: implementing Saga with Temporal

November 8, 2022
Temporal Workflow Orchestration
Microservices

Workflow Orchestration with Temporal and Spring Boot

October 29, 2022

Recent Articles

gRPC Bidirectional Streaming with Code Example

gRPC Bidirectional Streaming with Code Example

February 17, 2023
gRPC Client Streaming

gRPC Client Streaming

January 20, 2023
Distributed transaction in microservices using Saga

Distributed Transactions in Microservices: implementing Saga with Temporal

November 8, 2022
Temporal Workflow Orchestration

Workflow Orchestration with Temporal and Spring Boot

October 29, 2022
  • Trending
  • Comments
  • Latest
Deploying a RESTful Spring Boot Microservice on Kubernetes

Deploying a RESTful Spring Boot Microservice on Kubernetes

August 18, 2021
Temporal Workflow Orchestration

Workflow Orchestration with Temporal and Spring Boot

October 29, 2022
gRPC Interceptor: unary interceptor with code example

gRPC Interceptor: unary interceptor with code example

April 30, 2022
Microservices inter-process communication using gRPC

gRPC for microservices communication

August 29, 2021
Calculus

Functional Programming in Java

0
Java Streams: stream creation with examples

Java Streams: stream creation with examples

0
Garbage Collection

Super Fast Garbage Collectors in Java

0
Java Streams: Stream Operation with Examples

Java Streams: Stream Operation with Examples

0
gRPC Bidirectional Streaming with Code Example

gRPC Bidirectional Streaming with Code Example

February 17, 2023
gRPC Client Streaming

gRPC Client Streaming

January 20, 2023
Distributed transaction in microservices using Saga

Distributed Transactions in Microservices: implementing Saga with Temporal

November 8, 2022
Temporal Workflow Orchestration

Workflow Orchestration with Temporal and Spring Boot

October 29, 2022
Facebook Twitter Pinterest

TECHDOZO

Simplifying modern tech stack!

Browse by Category

  • Bitesize
  • GraphQL
  • gRPC
  • Java
  • Kubernetes
  • Microservices
  • Spring Boot

Recent Articles

gRPC Bidirectional Streaming with Code Example

gRPC Bidirectional Streaming with Code Example

February 17, 2023
gRPC Client Streaming

gRPC Client Streaming

January 20, 2023

© 2023 Techdozo.

No Result
View All Result
  • Home
  • gRPC
  • Kubernetes
  • Microservices
  • GraphQL

© 2023 Techdozo.

Welcome Back!

Sign In with Google
OR

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In