Skip to content

Commit 4c6599c

Browse files
authored
Propagate Request Headers through API Client (#135)
## Changes Based on changes in databricks/databricks-sdk-go#572. This PR adds initial support for headers in ApiClient.java. The `*Impl` classes, when making a request, will construct a map of headers to be included in the request. These are passed through a new parameter in each of GET/PUT/POST/PATCH/DELETE. In the future, to support dynamic headers, we can modify our codegen template to add those fields to the headers map before calling the ApiClient. Alternatives considered: * **Adding headers in request objects directly**: this would not require any change in the ApiClient interface. Instead, we would introduce a new annotation for headers, much like what we do for query parameters, and reflectively scan the fields of each request object. We could do this, but for headers that have a fixed value (like `Content-Type` and `Accept`), these fields would essentially be private final fields that we could iterate through. Users can never interact with these fields, so it seems a bit unusual to have them in the request structure, a public interface. ## Tests <!-- How is this tested? -->
1 parent 1d47a74 commit 4c6599c

File tree

92 files changed

+1962
-858
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1962
-858
lines changed

.codegen/impl.java.tmpl

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package com.databricks.sdk.service.{{.Package.Name}};
44
import java.io.IOException;
55
import java.util.Collection;
66
import java.util.Map;
7+
import java.util.HashMap;
78

89
import com.databricks.sdk.core.ApiClient;
910
import com.databricks.sdk.core.DatabricksException;
@@ -26,18 +27,26 @@ class {{.PascalName}}Impl implements {{.PascalName}}Service {
2627
String path = {{if .PathParts -}}
2728
String.format("{{range .PathParts}}{{.Prefix}}{{if or .Field .IsAccountId}}%s{{end}}{{ end }}"{{ range .PathParts }}{{if .Field}}, request.get{{.Field.PascalName}}(){{ else if .IsAccountId }}, apiClient.configuredAccountID(){{end}}{{ end }})
2829
{{- else}}"{{.Path}}"{{end}};
30+
{{ template "headers" . }}
2931
{{if .Response -}}
30-
{{- if .Response.ArrayValue -}} return apiClient.getCollection(path, null, {{template "type" .Response.ArrayValue}}.class);
31-
{{- else if .Response.MapValue -}} return apiClient.getStringMap(path, request);
32+
{{- if .Response.ArrayValue -}} return apiClient.getCollection(path, null, {{template "type" .Response.ArrayValue}}.class, headers);
33+
{{- else if .Response.MapValue -}} return apiClient.getStringMap(path, request, headers);
3234
{{- else -}} return apiClient.{{.Verb}}(path{{if .Request}}, request{{end}}{{if .Response -}}, {{if .Response.ArrayValue }}Collection
3335
{{- else if .Response.MapValue }}Map
3436
{{- else}}{{template "type" .Response}}
35-
{{- end -}}{{else}}, Void{{end}}.class);{{end}}
37+
{{- end -}}{{else}}, Void{{end}}.class, headers);{{end}}
3638
{{- else -}}apiClient.{{.Verb}}(path{{if .Request}}, request{{end}}{{if .Response -}}, {{if .Response.ArrayValue }}Collection
3739
{{- else if .Response.MapValue }}Map
3840
{{- else}}{{template "type" .Response}}
39-
{{- end -}}{{else}}, Void{{end}}.class);
41+
{{- end -}}{{else}}, Void{{end}}.class, headers);
4042
{{end}}
4143
}
4244
{{end}}
43-
}
45+
}
46+
47+
{{ define "headers" -}}
48+
Map<String, String> headers = new HashMap<>();
49+
{{- range $key, $value := .FixedRequestHeaders }}
50+
headers.put("{{$key}}", "{{$value}}");
51+
{{- end -}}
52+
{{- end }}

databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313
import com.fasterxml.jackson.databind.ObjectMapper;
1414
import com.fasterxml.jackson.databind.SerializationFeature;
1515
import java.io.IOException;
16-
import java.util.Collection;
17-
import java.util.Map;
18-
import java.util.Random;
16+
import java.util.*;
1917
import org.slf4j.Logger;
2018
import org.slf4j.LoggerFactory;
2119

@@ -85,81 +83,105 @@ private ObjectMapper makeObjectMapper() {
8583
return mapper;
8684
}
8785

88-
private <I> Request withQuery(Request in, I entity) {
86+
private static <I> void setQuery(Request in, I entity) {
8987
if (entity == null) {
90-
return in;
88+
return;
9189
}
9290
for (GrpcTranscodingQueryParamsSerializer.HeaderEntry e :
9391
GrpcTranscodingQueryParamsSerializer.serialize(entity)) {
9492
in.withQueryParam(e.getKey(), e.getValue());
9593
}
96-
return in;
9794
}
9895

99-
public <I, O> Collection<O> getCollection(String path, I in, Class<O> element) {
96+
private static <I> void setHeaders(Request in, Map<String, String> headers) {
97+
if (headers == null) {
98+
return;
99+
}
100+
for (Map.Entry<String, String> e : headers.entrySet()) {
101+
in.withHeader(e.getKey(), e.getValue());
102+
}
103+
}
104+
105+
public <I, O> Collection<O> getCollection(
106+
String path, I in, Class<O> element, Map<String, String> headers) {
100107
return withJavaType(
101-
path, in, mapper.getTypeFactory().constructCollectionType(Collection.class, element));
108+
path,
109+
in,
110+
mapper.getTypeFactory().constructCollectionType(Collection.class, element),
111+
headers);
102112
}
103113

104-
public <I> Map<String, String> getStringMap(String path, I in) {
114+
public <I> Map<String, String> getStringMap(String path, I in, Map<String, String> headers) {
105115
return withJavaType(
106-
path, in, mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class));
116+
path,
117+
in,
118+
mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class),
119+
headers);
107120
}
108121

109-
protected <I, O> O withJavaType(String path, I in, JavaType javaType) {
122+
protected <I, O> O withJavaType(
123+
String path, I in, JavaType javaType, Map<String, String> headers) {
110124
try {
111-
Request request = withQuery(new Request("GET", path), in);
125+
Request request = prepareRequest("GET", path, in, headers);
112126
Response response = getResponse(request);
113127
return deserialize(response.getBody(), javaType);
114128
} catch (IOException e) {
115129
throw new DatabricksException("IO error: " + e.getMessage(), e);
116130
}
117131
}
118132

119-
public <O> O GET(String path, Class<O> target) {
120-
return GET(path, null, target);
133+
public <O> O GET(String path, Class<O> target, Map<String, String> headers) {
134+
return GET(path, null, target, headers);
121135
}
122136

123-
public <I, O> O GET(String path, I in, Class<O> target) {
137+
public <I, O> O GET(String path, I in, Class<O> target, Map<String, String> headers) {
124138
try {
125-
return execute(withQuery(new Request("GET", path), in), target);
139+
return execute(prepareRequest("GET", path, in, headers), target);
126140
} catch (IOException e) {
127141
throw new DatabricksException("IO error: " + e.getMessage(), e);
128142
}
129143
}
130144

131-
public <I, O> O POST(String path, I in, Class<O> target) {
145+
public <I, O> O POST(String path, I in, Class<O> target, Map<String, String> headers) {
132146
try {
133-
return execute(new Request("POST", path, serialize(in)), target);
147+
return execute(prepareRequest("POST", path, in, headers), target);
134148
} catch (IOException e) {
135149
throw new DatabricksException("IO error: " + e.getMessage(), e);
136150
}
137151
}
138152

139-
public <I, O> O PUT(String path, I in, Class<O> target) {
153+
public <I, O> O PUT(String path, I in, Class<O> target, Map<String, String> headers) {
140154
try {
141-
return execute(new Request("PUT", path, serialize(in)), target);
155+
return execute(prepareRequest("PUT", path, in, headers), target);
142156
} catch (IOException e) {
143157
throw new DatabricksException("IO error: " + e.getMessage(), e);
144158
}
145159
}
146160

147-
public <I, O> O PATCH(String path, I in, Class<O> target) {
161+
public <I, O> O PATCH(String path, I in, Class<O> target, Map<String, String> headers) {
148162
try {
149-
return execute(new Request("PATCH", path, serialize(in)), target);
163+
return execute(prepareRequest("PATCH", path, in, headers), target);
150164
} catch (IOException e) {
151165
throw new DatabricksException("IO error: " + e.getMessage(), e);
152166
}
153167
}
154168

155-
public <I, O> O DELETE(String path, I in, Class<O> target) {
169+
public <I, O> O DELETE(String path, I in, Class<O> target, Map<String, String> headers) {
156170
try {
157-
return execute(withQuery(new Request("DELETE", path), in), target);
171+
return execute(prepareRequest("DELETE", path, in, headers), target);
158172
} catch (IOException e) {
159173
throw new DatabricksException("IO error: " + e.getMessage(), e);
160174
}
161175
}
162176

177+
private <I> Request prepareRequest(
178+
String method, String path, I in, Map<String, String> headers) {
179+
Request req = new Request(method, path);
180+
setQuery(req, in);
181+
setHeaders(req, headers);
182+
return req;
183+
}
184+
163185
/**
164186
* Executes HTTP request with retries and converts it to proper POJO
165187
*
@@ -177,7 +199,6 @@ private <T> T execute(Request in, Class<T> target) throws IOException {
177199

178200
private Response getResponse(Request in) {
179201
in.withUrl(config.getHost() + in.getUrl());
180-
in.withHeader("Accept", "application/json");
181202
return executeInner(in);
182203
}
183204

databricks-sdk-java/src/main/java/com/databricks/sdk/service/billing/BillableUsageImpl.java

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

databricks-sdk-java/src/main/java/com/databricks/sdk/service/billing/BudgetsImpl.java

Lines changed: 19 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

databricks-sdk-java/src/main/java/com/databricks/sdk/service/billing/LogDeliveryImpl.java

Lines changed: 16 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

databricks-sdk-java/src/main/java/com/databricks/sdk/service/catalog/AccountMetastoreAssignmentsImpl.java

Lines changed: 19 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)