Generated Java protobuf and gRPC client for Flaggr
Java SDK
Generated Java protobuf types and gRPC service stubs for Flaggr. Use standard gRPC-Java to connect.
Installation
Maven
<dependencies>
<dependency>
<groupId>dev.flaggr</groupId>
<artifactId>flaggr-proto</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.62.2</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.62.2</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.62.2</version>
</dependency>
</dependencies>Gradle
dependencies {
implementation 'dev.flaggr:flaggr-proto:0.1.0'
implementation 'io.grpc:grpc-netty-shaded:1.62.2'
implementation 'io.grpc:grpc-protobuf:1.62.2'
implementation 'io.grpc:grpc-stub:1.62.2'
}gRPC Client Setup
import dev.flaggr.proto.v1.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class FlaggrClient {
private final EvaluationServiceGrpc.EvaluationServiceBlockingStub evaluationStub;
private final FlagStreamServiceGrpc.FlagStreamServiceStub streamStub;
private final ManagedChannel channel;
public FlaggrClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress(host, port)
.useTransportSecurity()
.build();
this.evaluationStub = EvaluationServiceGrpc.newBlockingStub(channel);
this.streamStub = FlagStreamServiceGrpc.newStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS);
}
}Flag Evaluation
Boolean
EvaluationContext context = EvaluationContext.newBuilder()
.setTargetingKey("user-456")
.putStringAttributes("plan", "enterprise")
.putStringAttributes("country", "AU")
.build();
ResolveBooleanResponse resp = evaluationStub.resolveBoolean(
ResolveBooleanRequest.newBuilder()
.setFlagKey("checkout-v2")
.setDefaultValue(false)
.setContext(context)
.setServiceId("web-app")
.build()
);
System.out.printf("checkout-v2 = %s (reason: %s)%n", resp.getValue(), resp.getReason());String
ResolveStringResponse resp = evaluationStub.resolveString(
ResolveStringRequest.newBuilder()
.setFlagKey("button-color")
.setDefaultValue("blue")
.setContext(context)
.setServiceId("web-app")
.build()
);Number
ResolveNumberResponse resp = evaluationStub.resolveNumber(
ResolveNumberRequest.newBuilder()
.setFlagKey("rate-limit")
.setDefaultValue(100.0)
.setContext(context)
.setServiceId("web-app")
.build()
);Object (JSON)
ResolveObjectResponse resp = evaluationStub.resolveObject(
ResolveObjectRequest.newBuilder()
.setFlagKey("banner-config")
.setDefaultValue("{\"text\":\"\",\"color\":\"blue\",\"dismissible\":true}")
.setContext(context)
.setServiceId("web-app")
.build()
);Bulk Evaluation
BulkEvaluateFlagsResponse resp = evaluationStub.bulkEvaluateFlags(
BulkEvaluateFlagsRequest.newBuilder()
.addFlagKeys("checkout-v2")
.addFlagKeys("dark-mode")
.addFlagKeys("rate-limit")
.setContext(context)
.setServiceId("web-app")
.build()
);
resp.getFlagsMap().forEach((key, result) -> {
System.out.printf("%s = %s (reason: %s)%n", key, result.getValue(), result.getReason());
});Streaming
Subscribe to real-time flag updates with server-side streaming:
import io.grpc.stub.StreamObserver;
streamStub.streamFlags(
StreamFlagsRequest.newBuilder()
.setServiceId("web-app")
.setEnvironment(Environment.ENVIRONMENT_PRODUCTION)
.setClientId("java-service-01")
.setApiToken("flg_your_token")
.build(),
new StreamObserver<FlagUpdate>() {
@Override
public void onNext(FlagUpdate update) {
switch (update.getEventType()) {
case FLAG_EVENT_TYPE_UPDATED:
System.out.printf("flag %s updated%n", update.getFlagKey());
break;
case FLAG_EVENT_TYPE_TOGGLED:
System.out.printf("flag %s toggled%n", update.getFlagKey());
break;
case FLAG_EVENT_TYPE_HEARTBEAT:
// connection alive
break;
default:
break;
}
}
@Override
public void onError(Throwable t) {
System.err.println("Stream error: " + t.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Stream completed");
}
}
);OpenFeature Integration
Use with the OpenFeature Java SDK:
import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.MutableContext;
public class Main {
public static void main(String[] args) {
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
// Register the Flaggr provider
api.setProvider(new FlaggrProvider("flaggr.dev", 443, "web-app", "flg_your_token"));
Client client = api.getClient();
MutableContext ctx = new MutableContext("user-456");
ctx.add("plan", "enterprise");
ctx.add("country", "AU");
boolean value = client.getBooleanValue("checkout-v2", false, ctx);
System.out.printf("checkout-v2 = %s%n", value);
}
}The FlaggrProvider wraps the gRPC client and implements the FeatureProvider interface. See the OpenFeature Java SDK docs for more on evaluation context, hooks, and event handling.
Async Client
For non-blocking evaluation, use the async stub:
EvaluationServiceGrpc.EvaluationServiceFutureStub asyncStub =
EvaluationServiceGrpc.newFutureStub(channel);
ListenableFuture<ResolveBooleanResponse> future = asyncStub.resolveBoolean(
ResolveBooleanRequest.newBuilder()
.setFlagKey("checkout-v2")
.setDefaultValue(false)
.setContext(context)
.setServiceId("web-app")
.build()
);
// Add callback or block on result
Futures.addCallback(future, new FutureCallback<ResolveBooleanResponse>() {
@Override
public void onSuccess(ResolveBooleanResponse result) {
System.out.printf("checkout-v2 = %s%n", result.getValue());
}
@Override
public void onFailure(Throwable t) {
System.err.println("Evaluation failed: " + t.getMessage());
}
}, MoreExecutors.directExecutor());