Skip to Content
How-To GuidesModify a gRPC Contract

Modify a gRPC Contract

All internal service-to-service calls use gRPC; REST endpoints are for external client access only. See API & gRPC Reference for the current 8 proto contracts and their ports — this page is the task workflow for changing one.

1. Edit the proto file

One file per service in backends/shared/src/main/proto/ (e.g. credential.proto), package matching the Java package (com.attestpro.credentialissuance):

syntax = "proto3"; package com.attestpro.credentialissuance; service CredentialIssuanceService { rpc IssueCredential(IssueCredentialRequest) returns (IssueCredentialResponse); rpc GetCredential(GetCredentialRequest) returns (CredentialResponse); } message IssueCredentialRequest { string issuer_id = 1; string subject_name = 2; string credential_type = 3; google.protobuf.Struct credential_data = 4; } message IssueCredentialResponse { string credential_id = 1; string shareable_link = 2; }

2. Regenerate Java stubs

The protobuf Gradle plugin (configured in backends/shared/build.gradle) regenerates stubs automatically on build:

./gradlew clean build # full rebuild, regenerates all stubs ./gradlew :backends:shared:compileProto # just the shared module

Generated output lands in backends/shared/build/generated/source/proto/main/{java,grpc}/com/attestpro/{service}/ and is checked into source control to avoid regenerating on every build.

3. Implement the RPC in the owning microservice

public class CredentialIssuanceServiceImpl extends CredentialIssuanceServiceGrpc.CredentialIssuanceServiceImplBase { @Override public void issueCredential( IssueCredentialRequest request, StreamObserver<IssueCredentialResponse> responseObserver) { try { IssueCredentialResponse response = IssueCredentialResponse.newBuilder() .setCredentialId(UUID.randomUUID().toString()) .setShareableLink("https://...") .build(); responseObserver.onNext(response); responseObserver.onCompleted(); } catch (Exception e) { responseObserver.onError(e); } } }

Register it as a Spring-managed gRPC service bean; the service’s application.yml sets its gRPC port (grpc.server.port) — see Internal gRPC mTLS for the mutual-TLS config every server/client channel requires.

4. Update the Core Engine gRPC client

Core Engine instantiates stubs at startup via Spring beans and is the only caller that knows multi-service workflows:

@Bean public CredentialIssuanceServiceGrpc.CredentialIssuanceServiceStub credentialIssuanceStub( ManagedChannel channel) { return CredentialIssuanceServiceGrpc.newStub(channel); }

If the proto changed shape, update the calling code that builds the request/response conversion.

5. Restart — stubs are not hot-reloaded

Unlike REST endpoints, gRPC stub changes require a full JVM restart of both the owning service and Core Engine to pick up regenerated classes.

Gotchas

  • Cross-module imports: only import from backends/shared or your own module. Generated proto stubs in shared are the one deliberate exception — every service depends on them.
  • Proto file organization: one file per service, named {service_name}.proto, package matching the Java package.
  • Service discovery (grpc.services.*.host/port in application.yml) resolves via Kubernetes DNS or the Docker Compose bridge network in deployed environments, and localhost when running services individually outside Docker — see Local Development.