or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-usage.mdconfiguration.mdexception-handling.mdindex.mdinterceptors.mdreactive-streaming.mdservice-implementation.md

client-usage.mddocs/

0

# Client Usage

1

2

Client functionality for consuming gRPC services with reactive programming support and configuration management. Clients are injected as CDI beans and provide reactive method signatures using Mutiny types.

3

4

## Capabilities

5

6

### @GrpcClient Annotation

7

8

Qualifies an injected gRPC client. The annotation provides configuration name resolution and supports programmatic creation of annotation literals.

9

10

```java { .api }

11

/**

12

* Qualifies an injected gRPC client.

13

*/

14

@Qualifier

15

@Target({ FIELD, PARAMETER })

16

@Retention(RUNTIME)

17

public @interface GrpcClient {

18

19

/**

20

* Constant value for {@link #value()} indicating that the annotated element's name should be used as-is.

21

*/

22

String ELEMENT_NAME = "<<element name>>";

23

24

/**

25

* The name is used to configure the gRPC client, e.g. the location, TLS/SSL, etc.

26

*

27

* @return the client name

28

*/

29

String value() default ELEMENT_NAME;

30

31

final class Literal extends AnnotationLiteral<GrpcClient> implements GrpcClient {

32

private static final long serialVersionUID = 1L;

33

private final String value;

34

35

/**

36

* Creates a new instance of {@link Literal}.

37

*

38

* @param value the name of the gRPC service, must not be {@code null}, must not be {@code blank}

39

* @return the literal instance.

40

*/

41

public static Literal of(String value);

42

43

/**

44

* @return the service name.

45

*/

46

public String value();

47

}

48

}

49

```

50

51

**Usage Examples:**

52

53

```java

54

import io.quarkus.grpc.GrpcClient;

55

import jakarta.inject.Inject;

56

57

public class GreetingClientService {

58

59

// Using field name as client name

60

@Inject

61

@GrpcClient

62

MutinyGreetingGrpc greeting;

63

64

// Using explicit client name

65

@Inject

66

@GrpcClient("user-service")

67

MutinyUserGrpc userService;

68

69

// Using method parameter injection

70

public void processGreeting(@GrpcClient("greeting") MutinyGreetingGrpc client) {

71

// Use client

72

}

73

}

74

```

75

76

### MutinyClient Interface

77

78

Represents a convenient Mutiny client generated for a gRPC service. Provides access to the underlying gRPC stub and supports creating new instances with custom stubs.

79

80

```java { .api }

81

/**

82

* Represents a convenient Mutiny client generated for a gRPC service.

83

*/

84

public interface MutinyClient<T extends AbstractStub<T>> {

85

86

/**

87

*

88

* @return the underlying stub

89

*/

90

T getStub();

91

92

MutinyClient<T> newInstanceWithStub(T stub);

93

}

94

```

95

96

**Usage Examples:**

97

98

```java

99

import io.quarkus.grpc.GrpcClient;

100

import io.quarkus.grpc.MutinyClient;

101

import io.grpc.stub.AbstractStub;

102

import io.smallrye.mutiny.Uni;

103

104

public class ProductClientService {

105

106

@Inject

107

@GrpcClient("product-service")

108

MutinyClient<ProductServiceGrpc.ProductServiceStub> productClient;

109

110

public Uni<Product> getProduct(Long productId) {

111

ProductRequest request = ProductRequest.newBuilder()

112

.setId(productId)

113

.build();

114

115

return productClient.getStub().getProduct(request);

116

}

117

118

public MutinyClient<ProductServiceGrpc.ProductServiceStub> withDeadline(Duration timeout) {

119

var stubWithDeadline = productClient.getStub()

120

.withDeadlineAfter(timeout.toMillis(), TimeUnit.MILLISECONDS);

121

return productClient.newInstanceWithStub(stubWithDeadline);

122

}

123

}

124

```

125

126

### Client Configuration

127

128

Clients are configured through application properties using the client name:

129

130

```properties

131

# Basic configuration

132

quarkus.grpc.clients.greeting.host=localhost

133

quarkus.grpc.clients.greeting.port=9000

134

135

# TLS configuration

136

quarkus.grpc.clients.user-service.host=secure-service.example.com

137

quarkus.grpc.clients.user-service.port=443

138

quarkus.grpc.clients.user-service.ssl.trust-store=path/to/truststore.p12

139

quarkus.grpc.clients.user-service.ssl.trust-store-password=secret

140

141

# Load balancing

142

quarkus.grpc.clients.payment-service.host=payment-service

143

quarkus.grpc.clients.payment-service.port=9000

144

quarkus.grpc.clients.payment-service.load-balancing-policy=round_robin

145

```

146

147

### Client Utilities

148

149

Utility class for working with gRPC clients, including header attachment and proxy handling.

150

151

```java { .api }

152

/**

153

* gRPC client utilities

154

*/

155

public class GrpcClientUtils {

156

157

/**

158

* Attach headers to a gRPC client.

159

*

160

* To make a call with headers, first invoke this method and then perform the intended call with the <b>returned</b> client

161

*

162

* @param client any kind of gRPC client

163

* @param extraHeaders headers to attach

164

* @param <T> type of the client

165

* @return a client with headers attached

166

*/

167

public static <T> T attachHeaders(T client, Metadata extraHeaders);

168

169

public static <T> T getProxiedObject(T client);

170

}

171

```

172

173

**Usage Examples:**

174

175

```java

176

import io.quarkus.grpc.GrpcClientUtils;

177

import io.grpc.Metadata;

178

import io.grpc.Metadata.Key;

179

180

public class AuthenticatedClientService {

181

182

@Inject

183

@GrpcClient("secure-service")

184

MutinySecureServiceGrpc secureClient;

185

186

public Uni<SecureResponse> callSecureService(String token, SecureRequest request) {

187

// Create headers

188

Metadata headers = new Metadata();

189

Key<String> authKey = Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);

190

headers.put(authKey, "Bearer " + token);

191

192

// Attach headers to client

193

var clientWithHeaders = GrpcClientUtils.attachHeaders(secureClient, headers);

194

195

// Make the call

196

return clientWithHeaders.secureCall(request);

197

}

198

199

public Uni<UserInfo> getUserInfo(String userId) {

200

// Get actual client instance (unwrap proxy if needed)

201

var actualClient = GrpcClientUtils.getProxiedObject(secureClient);

202

203

UserRequest request = UserRequest.newBuilder()

204

.setUserId(userId)

205

.build();

206

207

return actualClient.getUserInfo(request);

208

}

209

}

210

```

211

212

### Reactive Call Patterns

213

214

Clients support all gRPC call patterns using Mutiny reactive types:

215

216

```java

217

public class ComprehensiveClientExample {

218

219

@Inject

220

@GrpcClient("data-service")

221

MutinyDataServiceGrpc dataClient;

222

223

// Unary call: request -> Uni<response>

224

public Uni<DataResponse> getData(String id) {

225

DataRequest request = DataRequest.newBuilder().setId(id).build();

226

return dataClient.getData(request);

227

}

228

229

// Server streaming: request -> Multi<response>

230

public Multi<DataItem> streamData(String query) {

231

StreamRequest request = StreamRequest.newBuilder().setQuery(query).build();

232

return dataClient.streamData(request);

233

}

234

235

// Client streaming: Multi<request> -> Uni<response>

236

public Uni<UploadResponse> uploadData(Multi<DataChunk> chunks) {

237

return dataClient.uploadData(chunks);

238

}

239

240

// Bidirectional streaming: Multi<request> -> Multi<response>

241

public Multi<ProcessedData> processData(Multi<RawData> rawData) {

242

return dataClient.processData(rawData);

243

}

244

}

245

```

246

247

### Error Handling

248

249

Client errors are propagated as Mutiny failures and can be handled using standard reactive patterns:

250

251

```java

252

public class ErrorHandlingExample {

253

254

@Inject

255

@GrpcClient("unreliable-service")

256

MutinyUnreliableServiceGrpc client;

257

258

public Uni<ServiceResponse> callWithRetry(ServiceRequest request) {

259

return client.callService(request)

260

.onFailure(StatusRuntimeException.class)

261

.retry().withBackOff(Duration.ofSeconds(1)).atMost(3)

262

.onFailure().transform(ex -> {

263

if (ex instanceof StatusRuntimeException) {

264

StatusRuntimeException sre = (StatusRuntimeException) ex;

265

return new ServiceException("Service call failed: " + sre.getStatus());

266

}

267

return ex;

268

});

269

}

270

}

271

```

272

273

### Programmatic Client Creation

274

275

For dynamic client creation, use CDI programmatic lookup with GrpcClient.Literal:

276

277

```java

278

import jakarta.enterprise.inject.Instance;

279

import io.quarkus.grpc.GrpcClient;

280

281

@ApplicationScoped

282

public class DynamicClientService {

283

284

@Inject

285

Instance<Object> instance;

286

287

public <T> T getClient(String serviceName, Class<T> clientType) {

288

return instance.select(clientType, GrpcClient.Literal.of(serviceName)).get();

289

}

290

291

public Uni<GreetingResponse> greetDynamically(String serviceName, String name) {

292

MutinyGreetingGrpc client = getClient(serviceName, MutinyGreetingGrpc.class);

293

294

GreetingRequest request = GreetingRequest.newBuilder()

295

.setName(name)

296

.build();

297

298

return client.greet(request);

299

}

300

}

301

```