How to Push to a GitHub Repository in IntelliJ
This blog guides you through the standard procedure for adding a gRPC endpoint to the order-service project. The primary goal is to handle "create new order" requests from external clients via gRPC. This process involves calling an internal user-service to validate user information.
.proto file clearly defines the service interface and message structures, ensuring type safety at compile time.First, define the service contract by creating a .proto file in the src/main/proto directory.
syntax = "proto3";
package com.abc.order.grpc;
// Java code generation options
option java_multiple_files = true;
option java_package = "com.abc.order.grpc";
option java_outer_classname = "OrderProto";
// The order creation service
service OrderCreationService {
// A Remote Procedure Call (RPC) to create a new order
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {}
}
// The request message for creating an order
message CreateOrderRequest {
string user_id = 1; // The ID of the user placing the order
repeated string product_ids = 2; // A list of product IDs to order
string correlation_id = 3; // A unique ID for request tracing
}
// The response message after creating an order
message CreateOrderResponse {
bool success = 1; // Indicates if the operation was successful
string order_id = 2; // The ID of the created order
string message = 3; // A result message
}
service OrderCreationService: Defines the CreateOrder method that clients can call.message CreateOrderRequest: Structures the parameters needed for order creation, like user_id and product_ids.message CreateOrderResponse: Structures the result to be returned after order creation, like the order_id and status.Configure pom.xml to automatically generate Java code from the .proto file and include it in the build. This is a standard configuration for gRPC projects.
<properties>
<grpc.version>1.73.0</grpc.version>
<protobuf.version>4.31.1</protobuf.version>
<grpc.spring.boot.starter.version>5.2.0</grpc.spring.boot.starter.version>
</properties>
<dependencies>
<dependency>
<groupId>io.github.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>${grpc.spring.boot.starter.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
The protobuf-maven-plugin and build-helper-maven-plugin configurations are required.
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.25.1: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>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/protobuf/java</source>
<source>${project.build.directory}/generated-sources/protobuf/grpc-java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Implement the business logic for creating an order by extending the auto-generated base class.
package com.abc.orderservice.grpc;
// ... (necessary imports)
import com.abc.orderservice.service.InternalOrderProcessingService;
import com.abc.orderservice.service.UserService;
import com.abc.order.grpc.OrderCreationServiceGrpc;
import com.abc.order.grpc.CreateOrderRequest;
import com.abc.order.grpc.CreateOrderResponse;
import io.grpc.stub.StreamObserver;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.lognet.springboot.grpc.GRpcService;
@GRpcService // ◀ Auto-registers this class as a gRPC service
@RequiredArgsConstructor
@Slf4j
public class OrderCreationServiceImpl extends OrderCreationServiceGrpc.OrderCreationServiceImplBase { // ◀ Extends the auto-generated class
private final UserService userService;
private final InternalOrderProcessingService orderProcessingService;
@Override
public void createOrder(CreateOrderRequest request, StreamObserver<CreateOrderResponse> responseObserver) {
log.info("🛍️ Received new order request: User ID '{}'", request.getUserId());
try {
// 1. Call UserService to validate the user
boolean isUserValid = userService.validateUser(request.getUserId());
if (!isUserValid) {
throw new IllegalArgumentException("Invalid User ID.");
}
log.info("✅ User ID '{}' is valid.", request.getUserId());
// 2. Execute the order processing logic
String orderId = orderProcessingService.create(request.getUserId(), request.getProductIdsList());
log.info("✅ Order created successfully. Order ID: {}", orderId);
// 3. Send a success response
CreateOrderResponse response = CreateOrderResponse.newBuilder()
.setSuccess(true)
.setOrderId(orderId)
.setMessage("Order created successfully.")
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
} catch (Exception e) {
log.error("❌ Error during order creation", e);
// 4. Send a failure response
CreateOrderResponse response = CreateOrderResponse.newBuilder()
.setSuccess(false)
.setMessage("Order creation failed: " + e.getMessage())
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
}
@GRpcService: This annotation from the lognet starter registers the class as a gRPC service in the Spring context.extends OrderCreationServiceGrpc.OrderCreationServiceImplBase: You must extend the abstract class generated by the protobuf-maven-plugin to implement the RPC methods defined in your .proto file.StreamObserver: This is gRPC's asynchronous callback mechanism. Use responseObserver.onNext() to send the response and responseObserver.onCompleted() to close the communication. You must call these even if an error occurs.@RequiredArgsConstructor to inject other Spring services like UserService.Specify the port for the gRPC server in application.yaml.
# application.yml
grpc:
server:
port: 9090
Now, when you run the application, it will be ready to accept new order requests on port 9090.
Comments
Post a Comment