[gRPC] server of Java and client of Typescript
Great! To develop two applications – a gRPC client in TypeScript using Avro and a gRPC server in Java using Avro, we’ll follow these steps. I’ll break it down into the server and client components.
Plan Overview
Server Application: Java-based gRPC server with Avro serialization.
- Exposes a gRPC service that sends/receives Avro-encoded data.
- Uses Gradle to manage dependencies.
Client Application: TypeScript-based gRPC client.
- Communicates with the gRPC server using Avro-encoded messages.
- Uses grpc-web and a gRPC gateway to bridge between gRPC and the web frontend.
1. gRPC Server in Java with Avro
Project Setup for Server
- Create a new Gradle project.
- Add the necessary dependencies (gRPC, Avro, and protobuf).
Server Directory Structure
grpc-server-java/
├── build.gradle.kts
├── settings.gradle.kts
├── src/
│ ├── main/
│ │ ├── java/ # Java source files
│ │ │ └── com/example/service/ # Service implementation
│ │ └── proto/ # Protobuf and Avro schema files
└── └── resources/ # Application config files (if needed)
Step 1: Add Dependencies in build.gradle.kts
plugins {
java
id("com.google.protobuf") version "0.9.1" // gRPC plugin
id("com.github.davidmc24.gradle.plugin.avro") version "1.6.0" // Avro plugin
id("application")
}
repositories {
mavenCentral()
}
dependencies {
implementation("io.grpc:grpc-netty-shaded:1.56.0")
implementation("io.grpc:grpc-protobuf:1.56.0")
implementation("io.grpc:grpc-stub:1.56.0")
implementation("com.google.protobuf:protobuf-java:3.22.0")
// Avro dependencies
implementation("org.apache.avro:avro:1.11.1")
// Protobuf compiler for code generation
compileOnly("com.google.protobuf:protoc:3.22.0")
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.22.0"
}
plugins {
create("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:1.56.0"
}
}
generateProtoTasks {
all().forEach { task ->
task.plugins {
create("grpc")
}
}
}
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
application {
mainClass.set("com.example.service.GrpcServer")
}
Step 2: Define .proto
and Avro Schema Files
Place your .proto
file in the src/main/proto/
folder:
// src/main/proto/user_service.proto
syntax = "proto3";
package example;
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
string userId = 1;
}
message UserResponse {
string userId = 1;
string name = 2;
int32 age = 3;
}
And define the Avro schema in a .avsc
file:
// src/main/resources/avro/user.avsc
{
"type": "record",
"name": "User",
"namespace": "com.example.avro",
"fields": [
{ "name": "userId", "type": "string" },
{ "name": "name", "type": "string" },
{ "name": "age", "type": "int" }
]
}
Step 3: Implement the gRPC Service
Create the Java implementation of the gRPC service.
// src/main/java/com/example/service/UserServiceImpl.java
package com.example.service;
import com.example.proto.UserRequest;
import com.example.proto.UserResponse;
import com.example.proto.UserServiceGrpc;
import io.grpc.stub.StreamObserver;
public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(UserRequest request, StreamObserver<UserResponse> responseObserver) {
// Example: Return a UserResponse with dummy data
UserResponse response = UserResponse.newBuilder()
.setUserId(request.getUserId())
.setName("John Doe")
.setAge(25)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
Step 4: Start the gRPC Server
Create the gRPC server main class.
// src/main/java/com/example/service/GrpcServer.java
package com.example.service;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
public class GrpcServer {
public static void main(String[] args) throws IOException, InterruptedException {
Server server = ServerBuilder.forPort(8080)
.addService(new UserServiceImpl())
.build();
System.out.println("Server started on port 8080");
server.start();
server.awaitTermination();
}
}
Step 5: Build and Run the Server
Run the following commands:
./gradlew clean build
./gradlew run
The server should start on port 8080.
2. gRPC Client in TypeScript with Avro
Project Setup for Client
- Create a new TypeScript project.
- Use
grpc-web
to communicate with the Java gRPC server. - Use
avsc
to handle Avro encoding and decoding in TypeScript.
Step 1: Install Dependencies
Run the following commands to set up the client:
mkdir grpc-client-ts
cd grpc-client-ts
npm init -y
npm install grpc-web google-protobuf avsc @types/google-protobuf --save
Step 2: Generate TypeScript gRPC Stubs
Use protoc
to generate TypeScript code for your gRPC service.
protoc -I=. user_service.proto \
--js_out=import_style=commonjs:./src \
--grpc-web_out=import_style=typescript,mode=grpcwebtext:./src
This will generate the necessary TypeScript files in the src/
directory.
Step 3: Implement the gRPC Client
Create a TypeScript client to call the gRPC service.
// src/client.ts
import { UserServiceClient } from './user_service_pb_service';
import { UserRequest, UserResponse } from './user_service_pb';
import * as avro from 'avsc';
// Define the Avro schema for decoding
const userSchema = avro.Type.forSchema({
type: 'record',
name: 'User',
fields: [
{ name: 'userId', type: 'string' },
{ name: 'name', type: 'string' },
{ name: 'age', type: 'int' },
],
});
const client = new UserServiceClient('http://localhost:8080', null, null);
const request = new UserRequest();
request.setUserid('123');
client.getUser(request, {}, (err, response: UserResponse) => {
if (err) {
console.error('Error:', err);
return;
}
// Decode the Avro-encoded response
const user = userSchema.fromBuffer(response.serializeBinary());
console.log('Received user:', user);
});
Step 4: Run the Client
Use the following command to run the client:
npx ts-node src/client.ts
Make sure the Java server is running before executing the client.
Conclusion
You now have a working gRPC server in Java with Avro serialization and a TypeScript gRPC client using grpc-web
. This setup allows seamless communication between the two applications.
Let me know if you encounter any issues or need further help!
댓글
댓글 쓰기