Skip to content

Commit cf380e2

Browse files
authored
Documentation about compatibility headers.
Original Pull Request #2093 Closes #2088
1 parent 266fb73 commit cf380e2

File tree

2 files changed

+124
-12
lines changed

2 files changed

+124
-12
lines changed

Diff for: src/main/asciidoc/reference/elasticsearch-clients.adoc

+23
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,29 @@ Default is 5 sec.
151151
IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens.
152152
If this is used in the reactive setup, the supplier function *must not* block!
153153

154+
=== Elasticsearch 7 compatibility headers
155+
156+
When using Spring Data Elasticsearch 4 - which uses the Elasticsearch 7 client libraries - and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers
157+
https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticserach documentation].
158+
This should be done using a header supplier like shown above:
159+
160+
====
161+
[source,java]
162+
----
163+
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
164+
configurationBuilder //
165+
// ...
166+
.withHeaders(() -> {
167+
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
168+
defaultCompatibilityHeaders.add("Accept",
169+
"application/vnd.elasticsearch+json;compatible-with=7");
170+
defaultCompatibilityHeaders.add("Content-Type",
171+
"application/vnd.elasticsearch+json;compatible-with=7");
172+
return defaultCompatibilityHeaders;
173+
});
174+
----
175+
====
176+
154177
[[elasticsearch.clients.logging]]
155178
== Client Logging
156179

Diff for: src/test/java/org/springframework/data/elasticsearch/client/RestClientsTest.java

+101-12
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
import java.util.function.Consumer;
3333
import java.util.stream.Stream;
3434

35+
import org.elasticsearch.action.index.IndexRequest;
3536
import org.elasticsearch.client.RequestOptions;
3637
import org.elasticsearch.client.RestHighLevelClient;
38+
import org.elasticsearch.xcontent.XContentType;
3739
import org.junit.jupiter.api.DisplayName;
3840
import org.junit.jupiter.api.extension.ExtendWith;
3941
import org.junit.jupiter.params.ParameterizedTest;
@@ -66,10 +68,6 @@ void shouldUseConfiguredProxy(ClientUnderTestFactory clientUnderTestFactory, Hov
6668
wireMockServer(server -> {
6769

6870
// wiremock is the dummy server, hoverfly the proxy
69-
WireMock.configureFor(server.port());
70-
stubForElasticsearchVersionCheck();
71-
stubFor(head(urlEqualTo("/")).willReturn(aResponse() //
72-
.withHeader("Content-Type", "application/json; charset=UTF-8")));
7371

7472
String serviceHost = "localhost:" + server.port();
7573
String proxyHost = "localhost:" + hoverfly.getHoverflyConfig().getProxyPort();
@@ -95,12 +93,6 @@ void shouldUseConfiguredProxy(ClientUnderTestFactory clientUnderTestFactory, Hov
9593
void shouldConfigureClientAndSetAllRequiredHeaders(ClientUnderTestFactory clientUnderTestFactory) {
9694
wireMockServer(server -> {
9795

98-
WireMock.configureFor(server.port());
99-
100-
stubForElasticsearchVersionCheck();
101-
stubFor(head(urlEqualTo("/")).willReturn(aResponse() //
102-
.withHeader("Content-Type", "application/json; charset=UTF-8")));
103-
10496
HttpHeaders defaultHeaders = new HttpHeaders();
10597
defaultHeaders.addAll("def1", Arrays.asList("def1-1", "def1-2"));
10698
defaultHeaders.add("def2", "def2-1");
@@ -156,6 +148,63 @@ void shouldConfigureClientAndSetAllRequiredHeaders(ClientUnderTestFactory client
156148
});
157149
}
158150

151+
@ParameterizedTest // #2088
152+
@MethodSource("clientUnderTestFactorySource")
153+
@DisplayName("should set compatibility headers")
154+
void shouldSetCompatibilityHeaders(ClientUnderTestFactory clientUnderTestFactory) {
155+
156+
wireMockServer(server -> {
157+
158+
stubFor(put(urlMatching("^/index/_doc/42(\\?.*)$?")) //
159+
.willReturn(jsonResponse("{\n" + //
160+
" \"_id\": \"42\",\n" + //
161+
" \"_index\": \"test\",\n" + //
162+
" \"_primary_term\": 1,\n" + //
163+
" \"_seq_no\": 0,\n" + //
164+
" \"_shards\": {\n" + //
165+
" \"failed\": 0,\n" + //
166+
" \"successful\": 1,\n" + //
167+
" \"total\": 2\n" + //
168+
" },\n" + //
169+
" \"_type\": \"_doc\",\n" + //
170+
" \"_version\": 1,\n" + //
171+
" \"result\": \"created\"\n" + //
172+
"}\n" //
173+
, 201) //
174+
.withHeader("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7") //
175+
.withHeader("X-Elastic-Product", "Elasticsearch")));
176+
177+
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
178+
configurationBuilder //
179+
.connectedTo("localhost:" + server.port()) //
180+
.withHeaders(() -> {
181+
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
182+
defaultCompatibilityHeaders.add("Accept", "application/vnd.elasticsearch+json;compatible-with=7");
183+
defaultCompatibilityHeaders.add("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7");
184+
return defaultCompatibilityHeaders;
185+
});
186+
187+
ClientConfiguration clientConfiguration = configurationBuilder.build();
188+
ClientUnderTest clientUnderTest = clientUnderTestFactory.create(clientConfiguration);
189+
190+
class Foo {
191+
public String id;
192+
193+
Foo(String id) {
194+
this.id = id;
195+
}
196+
}
197+
;
198+
199+
clientUnderTest.save(new Foo("42"));
200+
201+
verify(putRequestedFor(urlMatching("^/index/_doc/42(\\?.*)$?")) //
202+
.withHeader("Accept", new EqualToPattern("application/vnd.elasticsearch+json;compatible-with=7")) //
203+
.withHeader("Content-Type", new EqualToPattern("application/vnd.elasticsearch+json;compatible-with=7")) //
204+
);
205+
});
206+
}
207+
159208
private StubMapping stubForElasticsearchVersionCheck() {
160209
return stubFor(get(urlEqualTo("/")) //
161210
.willReturn(okJson("{\n" + //
@@ -179,6 +228,12 @@ private StubMapping stubForElasticsearchVersionCheck() {
179228
.withHeader("X-Elastic-Product", "Elasticsearch")));
180229
}
181230

231+
private StubMapping stubForHead() {
232+
return stubFor(head(urlEqualTo("/")) //
233+
.willReturn(ok() //
234+
.withHeader("X-Elastic-Product", "Elasticsearch")));
235+
}
236+
182237
/**
183238
* Consumer extension that catches checked exceptions and wraps them in a RuntimeException.
184239
*/
@@ -198,6 +253,8 @@ default void accept(WireMockServer wiremockConsumer) {
198253

199254
/**
200255
* starts a Wiremock server and calls consumer with the server as argument. Stops the server after consumer execution.
256+
* Before the consumer ids called the {@link #stubForHead()} and {@link #stubForElasticsearchVersionCheck()} are
257+
* registered.
201258
*
202259
* @param consumer the consumer
203260
*/
@@ -208,6 +265,10 @@ private void wireMockServer(WiremockConsumer consumer) {
208265
// test/resources/mappings
209266
try {
210267
wireMockServer.start();
268+
WireMock.configureFor(wireMockServer.port());
269+
stubForHead();
270+
stubForElasticsearchVersionCheck();
271+
211272
consumer.accept(wireMockServer);
212273
} finally {
213274
wireMockServer.shutdown();
@@ -224,6 +285,8 @@ interface ClientUnderTest {
224285
* @return true if successful
225286
*/
226287
boolean ping() throws Exception;
288+
289+
<T> void save(T entity) throws IOException;
227290
}
228291

229292
/**
@@ -253,7 +316,20 @@ protected String getDisplayName() {
253316
@Override
254317
ClientUnderTest create(ClientConfiguration clientConfiguration) {
255318
RestHighLevelClient client = RestClients.create(clientConfiguration).rest();
256-
return () -> client.ping(RequestOptions.DEFAULT);
319+
return new ClientUnderTest() {
320+
@Override
321+
public boolean ping() throws Exception {
322+
return client.ping(RequestOptions.DEFAULT);
323+
}
324+
325+
@Override
326+
public <T> void save(T entity) throws IOException {
327+
IndexRequest indexRequest = new IndexRequest("index");
328+
indexRequest.id("42");
329+
indexRequest.source(entity, XContentType.JSON);
330+
client.index(indexRequest, RequestOptions.DEFAULT);
331+
}
332+
};
257333
}
258334

259335
}
@@ -271,7 +347,20 @@ protected String getDisplayName() {
271347
@Override
272348
ClientUnderTest create(ClientConfiguration clientConfiguration) {
273349
ReactiveElasticsearchClient client = ReactiveRestClients.create(clientConfiguration);
274-
return () -> client.ping().block();
350+
return new ClientUnderTest() {
351+
@Override
352+
public boolean ping() throws Exception {
353+
return client.ping().block();
354+
}
355+
356+
@Override
357+
public <T> void save(T entity) throws IOException {
358+
IndexRequest indexRequest = new IndexRequest("index");
359+
indexRequest.id("42");
360+
indexRequest.source("{}", XContentType.JSON);
361+
client.index(indexRequest).block();
362+
}
363+
};
275364
}
276365
}
277366

0 commit comments

Comments
 (0)