diff --git a/rest-api-spec/build.gradle b/rest-api-spec/build.gradle index 73a9dd8fcdc8c..636ed83b13e2b 100644 --- a/rest-api-spec/build.gradle +++ b/rest-api-spec/build.gradle @@ -125,20 +125,14 @@ tasks.named("yamlRestCompatTest").configure { // This mean test cases where there is assertion on not finging by type won't work 'mget/11_default_index_type/Default index/type', 'mget/16_basic_with_types/Basic multi-get', - // 88 - 14 = 74 tests won't be fixed + // asserting about type not found won't work as we ignore the type information + 'explain/40_mix_typeless_typeful/Explain with typeless API on an index that has types', + // 89 - 15 = 74 tests won't be fixed 'cluster.voting_config_exclusions/10_basic/Throw exception when adding voting config exclusion and specifying both node_ids and node_names', 'cluster.voting_config_exclusions/10_basic/Throw exception when adding voting config exclusion without specifying nodes', 'count/11_basic_with_types/count body without query element', 'count/11_basic_with_types/count with body', 'count/11_basic_with_types/count with empty body', - 'explain/10_basic/Basic explain', - 'explain/10_basic/Basic explain with alias', - 'explain/11_basic_with_types/Basic explain', - 'explain/11_basic_with_types/Basic explain with alias', - 'explain/20_source_filtering/Source filtering', - 'explain/21_source_filtering_with_types/Source filtering', - 'explain/31_query_string_with_types/explain with query_string parameters', - 'explain/40_mix_typeless_typeful/Explain with typeless API on an index that has types', 'field_caps/30_filter/Field caps with index filter', 'get_source/11_basic_with_types/Basic with types', 'get_source/16_default_values_with_types/Default values', diff --git a/server/src/main/java/org/elasticsearch/action/explain/ExplainResponse.java b/server/src/main/java/org/elasticsearch/action/explain/ExplainResponse.java index aea881bfbead1..26dbd0187f8f3 100644 --- a/server/src/main/java/org/elasticsearch/action/explain/ExplainResponse.java +++ b/server/src/main/java/org/elasticsearch/action/explain/ExplainResponse.java @@ -12,6 +12,7 @@ import org.elasticsearch.Version; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.xcontent.ParseField; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ConstructingObjectParser; @@ -172,6 +173,10 @@ public static ExplainResponse fromXContent(XContentParser parser, boolean exists public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); builder.field(_INDEX.getPreferredName(), index); + if (builder.getRestApiVersion() == RestApiVersion.V_7) { + builder.field(MapperService.TYPE_FIELD_NAME, MapperService.SINGLE_MAPPING_NAME); + } + builder.field(_ID.getPreferredName(), id); builder.field(MATCHED.getPreferredName(), isMatch()); if (hasExplanation()) { diff --git a/server/src/main/java/org/elasticsearch/rest/action/search/RestExplainAction.java b/server/src/main/java/org/elasticsearch/rest/action/search/RestExplainAction.java index 2cd3f8889014d..1572d7597e406 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/search/RestExplainAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/search/RestExplainAction.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.explain.ExplainRequest; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.common.Strings; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.rest.BaseRestHandler; @@ -28,12 +29,20 @@ * Rest action for computing a score explanation for specific documents. */ public class RestExplainAction extends BaseRestHandler { + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] " + + "Specifying a type in explain requests is deprecated."; @Override public List routes() { return List.of( new Route(GET, "/{index}/_explain/{id}"), - new Route(POST, "/{index}/_explain/{id}")); + new Route(POST, "/{index}/_explain/{id}"), + Route.builder(GET, "/{index}/{type}/{id}/_explain") + .deprecated(TYPES_DEPRECATION_MESSAGE, RestApiVersion.V_7) + .build(), + Route.builder(POST, "/{index}/{type}/{id}/_explain") + .deprecated(TYPES_DEPRECATION_MESSAGE, RestApiVersion.V_7) + .build()); } @Override @@ -43,6 +52,9 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + if(request.getRestApiVersion() == RestApiVersion.V_7 && request.hasParam("type")) { + request.param("type"); + } ExplainRequest explainRequest = new ExplainRequest(request.param("index"), request.param("id")); explainRequest.parent(request.param("parent")); diff --git a/server/src/test/java/org/elasticsearch/rest/action/search/RestExplainActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/search/RestExplainActionTests.java new file mode 100644 index 0000000000000..6155289a1e488 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/rest/action/search/RestExplainActionTests.java @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.rest.action.search; + +import org.elasticsearch.action.explain.ExplainResponse; +import org.elasticsearch.core.RestApiVersion; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.test.rest.RestActionTestCase; +import org.junit.Before; +import org.mockito.Mockito; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class RestExplainActionTests extends RestActionTestCase { + final List contentTypeHeader = Collections.singletonList(compatibleMediaType(XContentType.VND_JSON, RestApiVersion.V_7)); + + @Before + public void setUpAction() { + RestExplainAction action = new RestExplainAction(); + controller().registerHandler(action); + verifyingClient.setExecuteVerifier((actionType, request) -> Mockito.mock(ExplainResponse.class)); + verifyingClient.setExecuteLocallyVerifier((actionType, request) -> Mockito.mock(ExplainResponse.class)); + } + + public void testTypeInPath() { + RestRequest deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Accept", contentTypeHeader)) + .withMethod(RestRequest.Method.GET) + .withPath("/some_index/some_type/some_id/_explain") + .build(); + dispatchRequest(deprecatedRequest); + assertWarnings(RestExplainAction.TYPES_DEPRECATION_MESSAGE); + + RestRequest validRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Accept", contentTypeHeader)) + .withMethod(RestRequest.Method.GET) + .withPath("/some_index/_explain/some_id") + .build(); + dispatchRequest(validRequest); + } + +}