Skip to content

Commit 3ce7cd5

Browse files
authored
Merge pull request #106 from qdrant/custom-headers
feat: Add support for custom headers
2 parents 4d4fe97 + af10911 commit 3ce7cd5

3 files changed

Lines changed: 73 additions & 37 deletions

File tree

src/main/java/io/qdrant/client/ApiKeyCredentials.java

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.qdrant.client;
2+
3+
import io.grpc.CallCredentials;
4+
import io.grpc.Metadata;
5+
import io.grpc.Status;
6+
import java.util.Collections;
7+
import java.util.Map;
8+
import java.util.concurrent.Executor;
9+
import javax.annotation.Nullable;
10+
11+
/** Used internally by the client to send the API key and any headers as gRPC metadata. */
12+
public class MetadataCredentials extends CallCredentials {
13+
@Nullable private final String apiKey;
14+
private final Map<String, String> headers;
15+
16+
/**
17+
* Instantiates a new instance of {@link MetadataCredentials}
18+
*
19+
* @param apiKey The API key to use for authentication.
20+
* @param headers Custom headers to send with every request.
21+
*/
22+
public MetadataCredentials(@Nullable String apiKey, Map<String, String> headers) {
23+
this.apiKey = apiKey;
24+
this.headers = headers != null ? headers : Collections.emptyMap();
25+
}
26+
27+
@Override
28+
public void applyRequestMetadata(
29+
RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) {
30+
appExecutor.execute(
31+
() -> {
32+
try {
33+
Metadata metadata = new Metadata();
34+
if (apiKey != null) {
35+
metadata.put(Metadata.Key.of("api-key", Metadata.ASCII_STRING_MARSHALLER), apiKey);
36+
}
37+
for (Map.Entry<String, String> entry : headers.entrySet()) {
38+
metadata.put(
39+
Metadata.Key.of(entry.getKey(), Metadata.ASCII_STRING_MARSHALLER),
40+
entry.getValue());
41+
}
42+
applier.apply(metadata);
43+
} catch (Throwable e) {
44+
applier.fail(Status.INTERNAL.withCause(e));
45+
}
46+
});
47+
}
48+
}

src/main/java/io/qdrant/client/QdrantGrpcClient.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.qdrant.client.grpc.QdrantGrpc.QdrantFutureStub;
1111
import io.qdrant.client.grpc.SnapshotsGrpc.SnapshotsFutureStub;
1212
import java.time.Duration;
13+
import java.util.Map;
1314
import java.util.concurrent.TimeUnit;
1415
import javax.annotation.Nullable;
1516
import org.slf4j.Logger;
@@ -193,8 +194,10 @@ public static class Builder {
193194
private final ManagedChannel channel;
194195
private final boolean shutdownChannelOnClose;
195196
private final boolean checkCompatibility;
197+
@Nullable private String apiKey;
196198
@Nullable private CallCredentials callCredentials;
197199
@Nullable private Duration timeout;
200+
@Nullable private Map<String, String> headers;
198201

199202
Builder(ManagedChannel channel, boolean shutdownChannelOnClose, boolean checkCompatibility) {
200203
this.channel = channel;
@@ -218,7 +221,7 @@ public static class Builder {
218221
* @return this
219222
*/
220223
public Builder withApiKey(String apiKey) {
221-
this.callCredentials = new ApiKeyCredentials(apiKey);
224+
this.apiKey = apiKey;
222225
return this;
223226
}
224227

@@ -237,6 +240,9 @@ public Builder withTimeout(@Nullable Duration timeout) {
237240
* Sets the credential data that will be propagated to the server via request metadata for each
238241
* RPC.
239242
*
243+
* <p>Note: If both {@link #withApiKey(String)} / {@link #withHeaders(Map)} and this method are
244+
* used, this method takes precedence and the API key and headers will be ignored.
245+
*
240246
* @param callCredentials The call credentials to use.
241247
* @return this
242248
*/
@@ -245,6 +251,17 @@ public Builder withCallCredentials(@Nullable CallCredentials callCredentials) {
245251
return this;
246252
}
247253

254+
/**
255+
* Sets custom headers to send with every gRPC request.
256+
*
257+
* @param headers The headers to send.
258+
* @return this
259+
*/
260+
public Builder withHeaders(Map<String, String> headers) {
261+
this.headers = headers;
262+
return this;
263+
}
264+
248265
/**
249266
* Builds a new instance of {@link QdrantGrpcClient}
250267
*
@@ -255,7 +272,13 @@ public QdrantGrpcClient build() {
255272
String clientVersion = Builder.class.getPackage().getImplementationVersion();
256273
checkVersionsCompatibility(clientVersion);
257274
}
258-
return new QdrantGrpcClient(channel, shutdownChannelOnClose, callCredentials, timeout);
275+
276+
CallCredentials credentials = this.callCredentials;
277+
if (credentials == null && (apiKey != null || headers != null)) {
278+
credentials = new MetadataCredentials(apiKey, headers);
279+
}
280+
281+
return new QdrantGrpcClient(channel, shutdownChannelOnClose, credentials, timeout);
259282
}
260283

261284
private static ManagedChannel createChannel(

0 commit comments

Comments
 (0)