Skip to content

Commit 4598b46

Browse files
authored
[Rest Api Compatibility] Typed endpoint for multiget api (#73878)
Retrofits typed api for M-get api removed in #46587 relates #51816
1 parent aa3fcc8 commit 4598b46

File tree

9 files changed

+136
-21
lines changed

9 files changed

+136
-21
lines changed

rest-api-spec/build.gradle

+16-17
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,11 @@ tasks.named("yamlRestCompatTest").configure {
121121
'search/160_exists_query/Test exists query on _type field',
122122
//type information is not stored, hence the the index will be found
123123
'termvectors/50_mix_typeless_typeful/Term vectors with typeless API on an index that has types',
124-
// 85 - 13 = 72 tests won't be fixed
124+
// mget - these use cases are no longer valid, because we always default to _doc.
125+
// This mean test cases where there is assertion on not finging by type won't work
126+
'mget/11_default_index_type/Default index/type',
127+
'mget/16_basic_with_types/Basic multi-get',
128+
// 88 - 14 = 74 tests won't be fixed
125129
'cluster.voting_config_exclusions/10_basic/Throw exception when adding voting config exclusion and specifying both node_ids and node_names',
126130
'cluster.voting_config_exclusions/10_basic/Throw exception when adding voting config exclusion without specifying nodes',
127131
'count/11_basic_with_types/count body without query element',
@@ -169,22 +173,6 @@ tasks.named("yamlRestCompatTest").configure {
169173
'indices.upgrade/10_basic/Upgrade indices disallow no indices',
170174
'indices.upgrade/10_basic/Upgrade indices disallow unavailable',
171175
'indices.upgrade/10_basic/Upgrade indices ignore unavailable',
172-
'mget/10_basic/Basic multi-get',
173-
'mget/11_default_index_type/Default index/type',
174-
'mget/14_alias_to_multiple_indices/Multi Get with alias that resolves to multiple indices',
175-
'mget/16_basic_with_types/Basic multi-get',
176-
'mget/17_default_index/Default index/type',
177-
'mget/18_non_existent_index_with_types/Non-existent index',
178-
'mget/19_missing_metadata_with_types/Missing metadata',
179-
'mget/21_alias_to_multiple_indices_with_types/Multi Get with alias that resolves to multiple indices',
180-
'mget/22_ids_with_types/IDs',
181-
'mget/23_stored_fields_with_types/Stored fields',
182-
'mget/41_routing_with_types/Routing',
183-
'mget/61_realtime_refresh_with_types/Realtime Refresh',
184-
'mget/71_source_filtering_with_types/Source filtering - exclude field',
185-
'mget/71_source_filtering_with_types/Source filtering - include field',
186-
'mget/71_source_filtering_with_types/Source filtering - include nested field',
187-
'mget/71_source_filtering_with_types/Source filtering - true/false',
188176
'mlt/20_docs/Basic mlt query with docs',
189177
'mlt/30_unlike/Basic mlt query with unlike',
190178
'search.aggregation/10_histogram/Deprecated _time order',
@@ -308,6 +296,17 @@ tasks.named("transformV7RestTests").configure({ task ->
308296
// overrides for indices.get_mapping
309297
task.replaceIsTrue("test_1.mappings.doc", "test_1.mappings._doc")
310298
task.replaceIsTrue("test_2.mappings.doc", "test_2.mappings._doc")
299+
// overrides for mget
300+
task.replaceValueInMatch("docs.0._type", "_doc" , "Basic multi-get") // index found, but no doc
301+
task.replaceValueInMatch("docs.0._type", "_doc", "Default index/type")
302+
task.replaceValueInMatch("docs.0._type", "_doc", "Non-existent index")
303+
task.replaceValueInMatch("docs.0._type", "_doc", "Missing metadata")
304+
task.replaceValueInMatch("docs.0._type", "_doc", "Multi Get with alias that resolves to multiple indices")
305+
task.replaceValueInMatch("docs.1._type", "_doc", "Multi Get with alias that resolves to multiple indices")
306+
task.replaceValueInMatch("docs.2._type", "_doc", "Multi Get with alias that resolves to multiple indices")
307+
task.replaceValueInMatch("docs.0._type", "_doc", "IDs")
308+
task.replaceValueInMatch("docs.1._type", "_doc", "IDs")
309+
task.replaceValueInMatch("docs.2._type", "_doc", "Routing")
311310
})
312311

313312
tasks.register('enforceYamlTestConvention').configure {

server/src/main/java/org/elasticsearch/action/get/MultiGetRequest.java

+8
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,20 @@
2020
import org.elasticsearch.core.Nullable;
2121
import org.elasticsearch.common.xcontent.ParseField;
2222
import org.elasticsearch.common.ParsingException;
23+
import org.elasticsearch.core.RestApiVersion;
2324
import org.elasticsearch.common.Strings;
2425
import org.elasticsearch.common.io.stream.StreamInput;
2526
import org.elasticsearch.common.io.stream.StreamOutput;
2627
import org.elasticsearch.common.io.stream.Writeable;
28+
import org.elasticsearch.common.logging.DeprecationLogger;
2729
import org.elasticsearch.common.lucene.uid.Versions;
2830
import org.elasticsearch.common.xcontent.ToXContentObject;
2931
import org.elasticsearch.common.xcontent.XContentBuilder;
3032
import org.elasticsearch.common.xcontent.XContentParser;
3133
import org.elasticsearch.common.xcontent.XContentParser.Token;
3234
import org.elasticsearch.index.VersionType;
3335
import org.elasticsearch.index.mapper.MapperService;
36+
import org.elasticsearch.rest.action.document.RestMultiGetAction;
3437
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
3538

3639
import java.io.IOException;
@@ -43,9 +46,11 @@
4346

4447
public class MultiGetRequest extends ActionRequest
4548
implements Iterable<MultiGetRequest.Item>, CompositeIndicesRequest, RealtimeRequest, ToXContentObject {
49+
private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(MultiGetRequest.class);
4650

4751
private static final ParseField DOCS = new ParseField("docs");
4852
private static final ParseField INDEX = new ParseField("_index");
53+
private static final ParseField TYPE = new ParseField("_type");
4954
private static final ParseField ID = new ParseField("_id");
5055
private static final ParseField ROUTING = new ParseField("routing");
5156
private static final ParseField VERSION = new ParseField("version");
@@ -383,6 +388,9 @@ private static void parseDocuments(XContentParser parser, List<Item> items, @Nul
383388
index = parser.text();
384389
} else if (ID.match(currentFieldName, parser.getDeprecationHandler())) {
385390
id = parser.text();
391+
} else if(parser.getRestApiVersion() == RestApiVersion.V_7 &&
392+
TYPE.match(currentFieldName,parser.getDeprecationHandler())) {
393+
deprecationLogger.compatibleApiWarning("mget_with_types", RestMultiGetAction.TYPES_DEPRECATION_MESSAGE);
386394
} else if (ROUTING.match(currentFieldName, parser.getDeprecationHandler())) {
387395
routing = parser.text();
388396
} else if (FIELDS.match(currentFieldName, parser.getDeprecationHandler())) {

server/src/main/java/org/elasticsearch/action/get/MultiGetResponse.java

+10
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,18 @@
1212
import org.elasticsearch.Version;
1313
import org.elasticsearch.action.ActionResponse;
1414
import org.elasticsearch.common.xcontent.ParseField;
15+
import org.elasticsearch.core.RestApiVersion;
1516
import org.elasticsearch.common.io.stream.StreamInput;
1617
import org.elasticsearch.common.io.stream.StreamOutput;
1718
import org.elasticsearch.common.io.stream.Writeable;
19+
import org.elasticsearch.common.logging.DeprecationLogger;
1820
import org.elasticsearch.common.xcontent.ToXContentObject;
1921
import org.elasticsearch.common.xcontent.XContentBuilder;
2022
import org.elasticsearch.common.xcontent.XContentParser;
2123
import org.elasticsearch.common.xcontent.XContentParser.Token;
2224
import org.elasticsearch.index.get.GetResult;
2325
import org.elasticsearch.index.mapper.MapperService;
26+
import org.elasticsearch.rest.action.document.RestMultiGetAction;
2427

2528
import java.io.IOException;
2629
import java.util.ArrayList;
@@ -29,8 +32,10 @@
2932
import java.util.List;
3033

3134
public class MultiGetResponse extends ActionResponse implements Iterable<MultiGetItemResponse>, ToXContentObject {
35+
private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(MultiGetResponse.class);
3236

3337
private static final ParseField INDEX = new ParseField("_index");
38+
private static final ParseField TYPE = new ParseField("_type");
3439
private static final ParseField ID = new ParseField("_id");
3540
private static final ParseField ERROR = new ParseField("error");
3641
private static final ParseField DOCS = new ParseField("docs");
@@ -94,6 +99,9 @@ public void writeTo(StreamOutput out) throws IOException {
9499
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
95100
builder.startObject();
96101
builder.field(INDEX.getPreferredName(), index);
102+
if (builder.getRestApiVersion() == RestApiVersion.V_7) {
103+
builder.field(MapperService.TYPE_FIELD_NAME, MapperService.SINGLE_MAPPING_NAME);
104+
}
97105
builder.field(ID.getPreferredName(), id);
98106
ElasticsearchException.generateFailureXContent(builder, params, exception, true);
99107
builder.endObject();
@@ -188,6 +196,8 @@ private static MultiGetItemResponse parseItem(XContentParser parser) throws IOEx
188196
case VALUE_STRING:
189197
if (INDEX.match(currentFieldName, parser.getDeprecationHandler())) {
190198
index = parser.text();
199+
} else if (TYPE.match(currentFieldName, parser.getDeprecationHandler())) {
200+
deprecationLogger.compatibleApiWarning("mget_with_types", RestMultiGetAction.TYPES_DEPRECATION_MESSAGE);
191201
} else if (ID.match(currentFieldName, parser.getDeprecationHandler())) {
192202
id = parser.text();
193203
}

server/src/main/java/org/elasticsearch/index/get/GetResult.java

+5
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
import org.elasticsearch.common.io.stream.StreamInput;
1919
import org.elasticsearch.common.io.stream.StreamOutput;
2020
import org.elasticsearch.common.io.stream.Writeable;
21+
import org.elasticsearch.common.logging.DeprecationLogger;
2122
import org.elasticsearch.common.xcontent.ToXContentObject;
2223
import org.elasticsearch.common.xcontent.XContentBuilder;
2324
import org.elasticsearch.common.xcontent.XContentHelper;
2425
import org.elasticsearch.common.xcontent.XContentParser;
2526
import org.elasticsearch.index.mapper.IgnoredFieldMapper;
2627
import org.elasticsearch.index.mapper.MapperService;
2728
import org.elasticsearch.index.mapper.SourceFieldMapper;
29+
import org.elasticsearch.rest.action.document.RestMultiGetAction;
2830
import org.elasticsearch.search.lookup.SourceLookup;
2931

3032
import java.io.IOException;
@@ -40,6 +42,7 @@
4042
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
4143

4244
public class GetResult implements Writeable, Iterable<DocumentField>, ToXContentObject {
45+
private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(GetResult.class);
4346

4447
public static final String _INDEX = "_index";
4548
public static final String _ID = "_id";
@@ -323,6 +326,8 @@ public static GetResult fromXContentEmbedded(XContentParser parser, String index
323326
} else if (token.isValue()) {
324327
if (_INDEX.equals(currentFieldName)) {
325328
index = parser.text();
329+
} else if (parser.getRestApiVersion() == RestApiVersion.V_7 && MapperService.TYPE_FIELD_NAME.equals(currentFieldName)) {
330+
deprecationLogger.compatibleApiWarning("mget_with_types", RestMultiGetAction.TYPES_DEPRECATION_MESSAGE);
326331
} else if (_ID.equals(currentFieldName)) {
327332
id = parser.text();
328333
} else if (_VERSION.equals(currentFieldName)) {

server/src/main/java/org/elasticsearch/rest/RestRequest.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,8 @@ public final boolean hasContentOrSourceParam() {
482482
*/
483483
public final XContentParser contentOrSourceParamParser() throws IOException {
484484
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
485-
return tuple.v1().xContent().createParser(xContentRegistry, LoggingDeprecationHandler.INSTANCE, tuple.v2().streamInput());
485+
return tuple.v1().xContent().createParserForCompatibility(xContentRegistry, LoggingDeprecationHandler.INSTANCE,
486+
tuple.v2().streamInput(), restApiVersion);
486487
}
487488

488489
/**

server/src/main/java/org/elasticsearch/rest/action/document/RestMultiGetAction.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import org.elasticsearch.action.get.MultiGetRequest;
1212
import org.elasticsearch.client.node.NodeClient;
13+
import org.elasticsearch.core.RestApiVersion;
1314
import org.elasticsearch.common.Strings;
1415
import org.elasticsearch.common.settings.Settings;
1516
import org.elasticsearch.common.xcontent.XContentParser;
@@ -25,6 +26,8 @@
2526
import static org.elasticsearch.rest.RestRequest.Method.POST;
2627

2728
public class RestMultiGetAction extends BaseRestHandler {
29+
public static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" +
30+
" Specifying types in multi get requests is deprecated.";
2831

2932
private final boolean allowExplicitIndex;
3033

@@ -38,7 +41,13 @@ public List<Route> routes() {
3841
new Route(GET, "/_mget"),
3942
new Route(POST, "/_mget"),
4043
new Route(GET, "/{index}/_mget"),
41-
new Route(POST, "/{index}/_mget"));
44+
new Route(POST, "/{index}/_mget"),
45+
Route.builder(GET, "/{index}/{type}/_mget")
46+
.deprecated(TYPES_DEPRECATION_MESSAGE, RestApiVersion.V_7)
47+
.build(),
48+
Route.builder(POST, "/{index}/{type}/_mget")
49+
.deprecated(TYPES_DEPRECATION_MESSAGE, RestApiVersion.V_7)
50+
.build());
4251
}
4352

4453
@Override
@@ -48,7 +57,9 @@ public String getName() {
4857

4958
@Override
5059
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
51-
60+
if (request.getRestApiVersion() == RestApiVersion.V_7 && request.param("type") != null) {
61+
request.param("type");
62+
}
5263
MultiGetRequest multiGetRequest = new MultiGetRequest();
5364
multiGetRequest.refresh(request.paramAsBoolean("refresh", multiGetRequest.refresh()));
5465
multiGetRequest.preference(request.param("preference"));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.rest.action.document;
10+
11+
import org.elasticsearch.action.get.MultiGetRequest;
12+
import org.elasticsearch.action.get.MultiGetResponse;
13+
import org.elasticsearch.core.RestApiVersion;
14+
import org.elasticsearch.common.bytes.BytesReference;
15+
import org.elasticsearch.common.settings.Settings;
16+
import org.elasticsearch.common.xcontent.XContentBuilder;
17+
import org.elasticsearch.common.xcontent.XContentFactory;
18+
import org.elasticsearch.common.xcontent.XContentType;
19+
import org.elasticsearch.rest.RestRequest;
20+
import org.elasticsearch.test.rest.FakeRestRequest;
21+
import org.elasticsearch.test.rest.RestActionTestCase;
22+
import org.junit.Before;
23+
import org.mockito.Mockito;
24+
25+
import java.util.Collections;
26+
import java.util.List;
27+
import java.util.Map;
28+
29+
import static org.hamcrest.Matchers.instanceOf;
30+
31+
public class RestMultiGetActionTests extends RestActionTestCase {
32+
XContentType VND_TYPE = randomVendorType();
33+
List<String> contentTypeHeader = Collections.singletonList(compatibleMediaType(VND_TYPE, RestApiVersion.V_7));
34+
35+
@Before
36+
public void setUpAction() {
37+
controller().registerHandler(new RestMultiGetAction(Settings.EMPTY));
38+
verifyingClient.setExecuteVerifier((actionType, request) -> {
39+
assertThat(request, instanceOf(MultiGetRequest.class));
40+
return Mockito.mock(MultiGetResponse.class);
41+
});
42+
}
43+
public void testTypeInPath() {
44+
RestRequest deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry())
45+
.withHeaders( Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader))
46+
.withMethod(RestRequest.Method.GET)
47+
.withPath("some_index/some_type/_mget")
48+
.build();
49+
dispatchRequest(deprecatedRequest);
50+
assertWarnings(RestMultiGetAction.TYPES_DEPRECATION_MESSAGE);
51+
}
52+
53+
public void testTypeInBody() throws Exception {
54+
XContentBuilder content = XContentFactory.contentBuilder(VND_TYPE).startObject()
55+
.startArray("docs")
56+
.startObject()
57+
.field("_index", "some_index")
58+
.field("_type", "_doc")
59+
.field("_id", "2")
60+
.endObject()
61+
.startObject()
62+
.field("_index", "test")
63+
.field("_id", "2")
64+
.endObject()
65+
.endArray()
66+
.endObject();
67+
68+
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
69+
.withPath("_mget")
70+
.withHeaders( Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader))
71+
.withContent(BytesReference.bytes(content), null)
72+
.build();
73+
dispatchRequest(request);
74+
assertWarnings(RestMultiGetAction.TYPES_DEPRECATION_MESSAGE);
75+
}
76+
77+
}

test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java

+4
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,10 @@ public String compatibleMediaType(XContentType type, RestApiVersion version) {
11571157
.responseContentTypeHeader(Map.of(MediaType.COMPATIBLE_WITH_PARAMETER_NAME, String.valueOf(version.major)));
11581158
}
11591159

1160+
public XContentType randomVendorType() {
1161+
return randomFrom(XContentType.VND_JSON, XContentType.VND_SMILE, XContentType.VND_CBOR, XContentType.VND_YAML);
1162+
}
1163+
11601164
public static class GeohashGenerator extends CodepointSetGenerator {
11611165
private static final char[] ASCII_SET = "0123456789bcdefghjkmnpqrstuvwxyz".toCharArray();
11621166

test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/MatchAssertion.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,6 @@ protected void doAssert(Object actualValue, Object expectedValue) {
8888
assertThat(actualValue, instanceOf(List.class));
8989
assertMap((List<?>) actualValue, matchesList((List<?>) expectedValue));
9090
}
91-
assertThat(expectedValue, equalTo(actualValue));
91+
assertThat(actualValue, equalTo(expectedValue));
9292
}
9393
}

0 commit comments

Comments
 (0)