Software Engineer's Blog

Adding a gRPC Endpoint to order-service: A Practical Guide

Adding a gRPC Endpoint to order-service: A Practical Guide

This guide walks you through the standard procedure for adding a new gRPC endpoint to the order-service Spring Boot project.
The goal is to expose an RPC method for creating a new order, while internally calling user-service to validate user information.

By the end of this guide, you will be able to:

  • Define a gRPC service using .proto
  • Generate Java stubs with Maven
  • Implement a gRPC service in Spring Boot
  • Integrate with other internal services
  • Run a gRPC server on a custom port

Why gRPC?

Modern distributed systems often require high performance and strict API contracts. gRPC provides:

  • High performance
    Uses HTTP/2 + Protobuf (binary), enabling low latency and efficient bandwidth use.
  • Strongly typed interfaces
    .proto files define all messages and RPC operations, giving compile-time safety.
  • Multi-language support
    Perfect for polyglot microservices — Java, Go, Node.js, Python, and more.

1. Define the API with Protocol Buffers

Start by creating a new .proto file under src/main/proto.

order.proto

syntax = "proto3";

package com.abc.order.grpc;

option java_multiple_files = true;
option java_package = "com.abc.order.grpc";
option java_outer_classname = "OrderProto";

// gRPC service definition
service OrderCreationService {
  rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {}
}

// Request message for creating an order
message CreateOrderRequest {
  string user_id = 1;
  repeated string product_ids = 2;
  string correlation_id = 3;
}

// Response message from the order creation
message CreateOrderResponse {
  bool success = 1;
  string order_id = 2;
  string message = 3;
}

Key Notes

  • repeated means the field behaves like a list.
  • correlation_id enables request tracking in distributed systems.
  • The .proto file acts as your API contract — the source of truth shared by all clients.

2. Configure Maven for gRPC Code Generation

Your pom.xml needs both gRPC dependencies and Protobuf code generation plugins.

Dependencies

<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>

Code Generation Plugins

These plugins generate Java classes from your .proto files and register them as project sources.

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.7.1</version>
        </extension>
    </extensions>

    <plugins>
        <!-- Generate protobuf and gRPC Java classes -->
        <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>

        <!-- Add generated files to the Java source path -->
        <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>

After the configuration is added, run:

mvn clean install

This creates Java stubs under:

target/generated-sources/

3. Implement the gRPC Service

Now extend the generated base class and implement your business logic.

OrderCreationServiceImpl.java

package com.abc.orderservice.grpc;

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
@RequiredArgsConstructor
@Slf4j
public class OrderCreationServiceImpl 
        extends OrderCreationServiceGrpc.OrderCreationServiceImplBase {

    private final UserService userService;
    private final InternalOrderProcessingService orderProcessingService;

    @Override
    public void createOrder(CreateOrderRequest request,
                            StreamObserver<CreateOrderResponse> responseObserver) {

        log.info("Received order request for user '{}'", request.getUserId());

        try {
            // Validate user through internal user-service
            boolean isUserValid = userService.validateUser(request.getUserId());
            if (!isUserValid) {
                throw new IllegalArgumentException("Invalid User ID");
            }

            // Execute order creation
            String orderId = orderProcessingService.create(
                    request.getUserId(),
                    request.getProductIdsList()
            );

            // Send 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("Order creation failed", e);

            CreateOrderResponse response = CreateOrderResponse.newBuilder()
                    .setSuccess(false)
                    .setMessage("Order creation failed: " + e.getMessage())
                    .build();

            responseObserver.onNext(response);
            responseObserver.onCompleted();
        }
    }
}

Important Notes

  • @GRpcService automatically registers the class as a gRPC endpoint.
  • You must call onNext() and onCompleted() even in error cases.
  • gRPC uses an asynchronous streaming model; StreamObserver is the callback interface.

4. Configure the gRPC Server Port

Add the following to your application.yml:

grpc:
  server:
    port: 9090

Your gRPC service is now accessible at:

localhost:9090

5. (Optional) Test with grpcurl

You can quickly test your endpoint with grpcurl:

grpcurl -plaintext \
  -d '{"user_id":"U1","product_ids":["P1","P2"],"correlation_id":"c-001"}' \
  localhost:9090 \
  com.abc.order.grpc.OrderCreationService/CreateOrder

Conclusion

You have successfully:

  • Defined a gRPC service
  • Generated Java stubs
  • Implemented a gRPC endpoint with Spring Boot
  • Integrated with internal services
  • Exposed the service on a custom port

This is the typical workflow for adding new RPC operations to your microservices that communicate using gRPC.