• Latest
gRPC on the Client Side

gRPC on the Client Side

March 18, 2023
LG G7 ThinQ Impressions!

LG G7 ThinQ Impressions!

March 20, 2023
Best Xbox zombie games

Best Xbox zombie games

March 20, 2023
New Allies delayed indefinitely on console

New Allies delayed indefinitely on console

March 20, 2023
Moto RAZR 2 Impressions: Nostalgia Reloaded?

Moto RAZR 2 Impressions: Nostalgia Reloaded?

March 20, 2023
The Entire Mystery joins Xbox Game Pass soon

The Entire Mystery joins Xbox Game Pass soon

March 20, 2023
Apple Watch Review!

Apple Watch Review!

March 20, 2023
The TRUTH About OnePlus Nord!

The TRUTH About OnePlus Nord!

March 20, 2023
Honor 70 Lite announced with Snapdragon 480+ and 50MP camera

Honor 70 Lite announced with Snapdragon 480+ and 50MP camera

March 20, 2023
16" Macbook Pro First Impressions!

16" Macbook Pro First Impressions!

March 20, 2023
Living with a Supercar! [Auto Focus Ep 3]

Living with a Supercar! [Auto Focus Ep 3]

March 20, 2023
Pocket City 2 Gameplay Shown Off in New Trailer, Release Date Set for Mid 2023 – TouchArcade

Pocket City 2 Gameplay Shown Off in New Trailer, Release Date Set for Mid 2023 – TouchArcade

March 20, 2023
RETRO TECH: DYNATAC

RETRO TECH: DYNATAC

March 20, 2023
Advertise with us
Monday, March 20, 2023
Bookmarks
  • Login
  • Register
GetUpdated
  • Game Updates
  • Mobile Gaming
  • Playstation News
  • Xbox News
  • Switch News
  • MMORPG
  • Game News
  • IGN
  • Retro Gaming
  • Tech News
  • Apple Updates
  • Jailbreak News
  • Mobile News
  • Software Development
  • Photography
  • Contact
No Result
View All Result
GetUpdated
No Result
View All Result
GetUpdated
No Result
View All Result
ADVERTISEMENT

gRPC on the Client Side

March 18, 2023
in Software Development
Reading Time:11 mins read
0 0
0
Share on FacebookShare on WhatsAppShare on Twitter


Most inter-systems communication components that use REST serialize their payload in JSON. As of now, JSON lacks a widely-used schema validation standard: JSON Schema is not widespread. Standard schema validation allows delegating the validation to a third-party library and being done with it. Without one, we must fall back to manual validation in the code. Worse, we must keep the validation code in sync with the schema.

XML has schema validation out-of-the-box: an XML document can declare a grammar that it must conform to. SOAP, being based on XML, benefits from it, too.

Other serialization alternatives have a schema validation option: e.g., Avro, Kryo, and Protocol Buffers. Interestingly enough, gRPC uses Protobuf to offer RPC across distributed components:

gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.

– Why gRPC?

Moreover, Protocol is a binary serialization mechanism, saving a lot of bandwidth. Thus, gRPC is an excellent option for inter-system communication. But if all your components talk gRPC, how can simple clients call them? In this post, we will build a gRPC service and show how to call it from cURL.

A Simple gRPC Service

The gRPC documentation is exhaustive, so here’s a summary:

  • gRPC is a Remote Procedure Call framework.
  • It works across a wide range of languages.
  • It relies on Protocol Buffers:

Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.

  • It’s part of the CNCF portfolio and is currently in the incubation stage.

Let’s set up our gRPC service. We will use Java, Kotlin, Spring Boot, and a dedicated gRPC Spring Boot integration project. The project structure holds two projects: one for the model and one for the code. Let’s start with the model project.

I didn’t want something complicated. Reusing a simple example is enough: the request sends a string, and the response prefixes it with Hello. We design this model in a dedicated Protobuf schema file:

syntax = "proto3";                                        //1

package ch.frankel.blog.grpc.model;                       //2

option java_multiple_files = true;                        //3
option java_package = "ch.frankel.blog.grpc.model";       //3
option java_outer_classname = "HelloProtos";              //3

service HelloService {                                    //4
    rpc SayHello (HelloRequest) returns (HelloResponse) {
    }
}

message HelloRequest {                                    //5
    string name = 1;                                      //6
}

message HelloResponse {                                   //7
    string message = 1;                                   //6
}

  1. Protobuf definition version
  2. Package
  3. Java-specific configuration
  4. Service definition
  5. Request definition
  6. Field definition: First comes the type, then the name, and finally, the order.
  7. Response definition

We shall use Maven to generate the Java boilerplate code:

<project>
  <dependencies>
    <dependency>
      <groupId>io.grpc</groupId>                         <!--1-->
      <artifactId>grpc-stub</artifactId>
      <version>${grpc.version}</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>                         <!--1-->
      <artifactId>grpc-protobuf</artifactId>
      <version>${grpc.version}</version>
    </dependency>
    <dependency>
      <groupId>jakarta.annotation</groupId>              <!--1-->
      <artifactId>jakarta.annotation-api</artifactId>
      <version>1.3.5</version>
      <optional>true</optional>
    </dependency>
  </dependencies>
  <build>
    <extensions>
      <extension>
        <groupId>kr.motd.maven</groupId>                 <!--2-->
        <artifactId>os-maven-plugin</artifactId>
        <version>1.7.1</version>
      </extension>
    </extensions>
    <plugins>
      <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>    <!--3-->
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>${protobuf-plugin.version}</version>
        <configuration>
          <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
          <pluginId>grpc-java</pluginId>
          <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>compile-custom</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

  1. Compile-time dependencies
  2. Sniff information about the Operating System; used in the next plugin
  3. Generate Java code from the proto file. 

After compilation, the structure should look something like the following:

Structure after compilation

We can package the classes in a JAR and use it in a web app project. The latter is in Kotlin, but only because it’s my favorite JVM language.

We only need a specific Spring Boot starter dependency to integrate gRPC endpoints with Spring Boot:

<dependency>
  <groupId>net.devh</groupId>
  <artifactId>grpc-server-spring-boot-starter</artifactId>
  <version>2.14.0.RELEASE</version>
</dependency>

Here’s the significant bit:

@GrpcService                                                        //1
class HelloService : HelloServiceImplBase() {                       //2
  override fun sayHello(
      request: HelloRequest,                                        //2
      observer: StreamObserver<HelloResponse>                       //3
  ) {
    with(observer) {
      val reply = HelloResponse.newBuilder()                        //2
                               .setMessage("Hello ${request.name}") //4
                               .build()
      onNext(reply)                                                 //5
      onCompleted()                                                 //5
    }
  }
}

  1. The grpc-server-spring-boot-starter detects the annotation and works its magic.
  2. Reference classes generated in the above project
  3. The method signature allows a StreamObserver parameter. The class comes from grpc-stub.jar. 
  4. Get the request and prefix it to build the response message.
  5. Play the events. 

We can now start the web app with ./mvnw spring-boot:run.

Testing the gRPC Service

The whole idea behind the post is that accessing the gRPC service with regular tools is impossible. To test, we need a dedicated tool nonetheless. I found grpcurl. Let’s install it and use it to list available services:

grpcurl --plaintext localhost:9090 list   #1-2

  1. List all available gRPC services without TLS verification. 
  2. To avoid clashes between gRPC and other channels, e.g., REST, Spring Boot uses another port.
ch.frankel.blog.grpc.model.HelloService   #1
grpc.health.v1.Health                     #2
grpc.reflection.v1alpha.ServerReflection  #2

  1. The gRPC service we defined
  2. Two additional services provided by the custom starter

We can also dive into the structure of the service:

grpcurl --plaintext localhost:9090 describe ch.frankel.blog.grpc.model.HelloService

service HelloService {
  rpc SayHello ( .ch.frankel.blog.grpc.model.HelloRequest ) returns ( .ch.frankel.blog.grpc.model.HelloResponse );
}

Finally, we can call the service with data:

grpcurl --plaintext -d '{"name": "John"}' localhost:9090 ch.frankel.blog.grpc.model.HelloService/SayHello

{
  "message": "Hello John"
}

Accessing the gRPC Service With Regular Tools

Imagine that we have a regular JavaScript client-side application that needs to access the gRPC service. What would be the alternatives?

The general approach is through grpc-web:

A JavaScript implementation of gRPC for browser clients. For more information, including a quick start, see the gRPC-web documentation.

gRPC-web clients connect to gRPC services via a special proxy; by default, gRPC-web uses Envoy.

In the future, we expect gRPC-web to be supported in language-specific web frameworks for languages such as Python, Java, and Node. For details, see the roadmap.

– grpc-web

The description states a single limitation: it works only for JavaScript (as of now). However, there’s another one. It’s pretty intrusive. You need to get the proto file, generate boilerplate code, and make your code call it. You must do it for every client type. Worse, if the proto file changes, you need to regenerate the client code in each of them.

An alternative exists, though, if you’re using an API Gateway. I’ll describe how to do it with Apache APISIX, but perhaps other gateways can do the same. grpc-transcode is a plugin that allows transcoding REST calls to gRPC and back again.

The first step is to register the proto file in Apache APISIX:

curl http://localhost:9180/apisix/admin/protos/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d "{ "content": "$(sed 's/"/\"/g' ../model/src/main/proto/model.proto)" }"

The second step is to create a route with the above plugin:

curl http://localhost:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
  "uri": "/helloservice/sayhello",                           #1
  "plugins": {
    "grpc-transcode": {
      "proto_id": "1",                                       #2
      "service": "ch.frankel.blog.grpc.model.HelloService",  #3
      "method": "SayHello"                                   #4
    }
  },
  "upstream": {
    "scheme": "grpc",
    "nodes": {
      "server:9090": 1
    }
  }
}'

  1. Define a granular route. 
  2. Reference the proto file defined in the previous command. 
  3. gRPC service
  4. gRPC method

At this point, any client can make an HTTP request to the defined endpoint. Apache APISIX will transcode the call to gRPC, forward it to the defined service, get the response, and transcode it again.

curl localhost:9080/helloservice/sayhello?name=John

Compared to grpc-web, the API Gateway approach allows sharing the proto file with a single component: the Gateway itself.

Benefits of Transcoding

At this point, we can leverage the capabilities of the API Gateway. Imagine we want a default value if no name is passed, e.g., World. Developers would happily set it in the code, but any change to the value would require a complete build and deployment. Changes can be nearly-instant if we put the default value in the Gateway’s routes processing chain. Let’s change our route accordingly:

curl http://localhost:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
  "uri": "/helloservice/sayhello",
  "plugins": {
    "grpc-transcode": {
      ...
    },
    "serverless-pre-function": {                    #1
      "phase": "rewrite",                           #2
      "functions" : [
        "return function(conf, ctx)                 #3
          local core = require("apisix.core")
          if not ngx.var.arg_name then
            local uri_args = core.request.get_uri_args(ctx)
            uri_args.name = "World"
            ngx.req.set_uri_args(uri_args)
          end
        end"
      ]
    }
  },
  "upstream": {
      ...
  }
}'

  1. Generic all-purpose plugin when none fits
  2. Rewrite the request.
  3. Magic Lua code that does the trick

Now, we can execute the request with an empty argument and get the expected result:

curl localhost:9080/helloservice/sayhello?name

{"message":"Hello World"}

Conclusion

In this post, we have briefly described gRPC and how it benefits inter-service communication. We developed a simple gRPC service using Spring Boot and grpc-server-spring-boot-starter. It comes at a cost, though: regular clients cannot access the service. We had to resort to grpcurl to test it. The same goes for clients based on JavaScript – or the browser.

To bypass this limitation, we can leverage an API Gateway. I demoed how to configure Apache APISIX with the grpc-transcode plugin to achieve the desired result.

The complete source code for this post can be found on GitHub.

To Go Further



Source link

ShareSendTweet
Previous Post

The BMW iX is Only Guilty of 1 Sin!

Next Post

IT IS FINALLY FINISHED!!

Related Posts

AWS CodeCommit and GitKraken Basics

March 20, 2023
0
0
AWS CodeCommit and GitKraken Basics
Software Development

Git is a source code management system that keeps track of the changes made to their codebase and collaborates with other...

Read more

Reliability Is Slowing You Down

March 19, 2023
0
0
Reliability Is Slowing You Down
Software Development

Three Hard Facts First, the complexity of your software systems is through the roof, and you have more external dependencies...

Read more
Next Post
IT IS FINALLY FINISHED!!

IT IS FINALLY FINISHED!!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

© 2021 GetUpdated – MW.

  • About
  • Advertise
  • Privacy & Policy
  • Terms & Conditions
  • Contact

No Result
View All Result
  • Game Updates
  • Mobile Gaming
  • Playstation News
  • Xbox News
  • Switch News
  • MMORPG
  • Game News
  • IGN
  • Retro Gaming
  • Tech News
  • Apple Updates
  • Jailbreak News
  • Mobile News
  • Software Development
  • Photography
  • Contact

Welcome Back!

Login to your account below

Forgotten Password? Sign Up

Create New Account!

Fill the forms bellow to register

All fields are required. Log In

Retrieve your password

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

Log In
Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?