Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatible logic for Removes typed endpoint from search and related APIs #54572

Merged
merged 53 commits into from
Jul 14, 2020

Conversation

pgomulka
Copy link
Contributor

@pgomulka pgomulka commented Apr 1, 2020

This adds a compatible APIs for typed endpoints removed in #41640

202 failing tests
These 2 tests are explicitly fixed by this PR
CompatRestIT. test {yaml=mtermvectors/21_deprecated_with_types/Deprecated camel case and _ parameters should fail in Term Vectors query}
CompatRestIT. test {yaml=mtermvectors/30_mix_typeless_typeful/mtermvectors without types on an index that has types}

I think more yml tests should be added to 7.x to cover these endpoints

17th june
1306tests | 197failures | 16ignored | 10m56.91sduration

fixed get/index tests
CompatRestIT. test {yaml=get/21_stored_fields_with_types/Stored fields}
CompatRestIT. test {yaml=get/71_source_filtering_with_types/Source
filtering}

CompatRestIT. test {yaml=index/70_mix_typeless_typeful/Index call that
introduces new field mappings}
CompatRestIT. test {yaml=index/70_mix_typeless_typeful/Index with
typeless API on an index that has types}

however the last one from get is still failing
CompatRestIT. test {yaml=get/100_mix_typeless_typeful/GET with typeless
API on an index that has
@pgomulka pgomulka added WIP :Core/Infra/REST API REST infrastructure and utilities labels Apr 1, 2020
@pgomulka pgomulka self-assigned this Apr 1, 2020
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (:Core/Infra/REST API)

@pgomulka pgomulka mentioned this pull request Apr 1, 2020
66 tasks
@pgomulka pgomulka requested a review from jakelandis April 1, 2020 12:19
Copy link
Contributor

@jakelandis jakelandis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really starting to take shape! I have a few comments and stopped with the repetitive comments (you can assume the same comment applies through out)

return List.of(new Route(GET, "/_mtermvectors"),
new Route(POST, "/_mtermvectors"),
new Route(GET, "/{index}/_mtermvectors"),
new Route(POST, "/{index}/_mtermvectors"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the the above non-typed endpoints be here ? Shouldn't the this error trying to register the route ?

Copy link
Contributor Author

@pgomulka pgomulka Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we allow registering same method and path but under different version. (if someone tried to register same method and path and version twice - it would end with error)
We need this because multi term vectors (and most multi-* api) can have a type in a body. So a typed request can be send via non-typed endpoint.


/**
* Parses a {@link RestRequest} body and returns a {@link MultiSearchTemplateRequest}
* @param typeConsumer - is a function used when parsing a request body. if it contains a types field it will consume it,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be re-named keyAllowed ? (or the like)

A function used to validate if a provided xContent key is allowed. This is useful for xContent compatibility to determine if a key is allowed to be present in version agnostic manner. The provided function should return false if the key is not allowed. 

(it is does not use the Consumer interface, and I believe it more general purpose then the just for types)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea, I wasn't sure typeConsumer was right as it was just too specific for type removal eample.
Will rename and update javadoc

import java.util.Set;
import java.util.function.Function;

public class TypeConsumer implements Function<String, Boolean> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class has a couple problems...
it is named Consumer, but actually a Function with a side effect
it requires an ordering between methods. (e.g. if you call hasTypes can yield different results then calling apply then hasTypes)

hasTypes() method feels utility like, and apply is a pure function (which shouldn't have side effects even local to it's own class).

Can we separate this into two classes , a utility class and pure function class. If you need to hold to the state returned by the function, whoever calls that function can take that responsibility.

Also, in tangent with my other comment on renaming the variable, I think the function class be be generalized as well KeyAllowed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree - the name is not right. The consumer was an initial idea but it ended up a function and I didn't change it accordingly. The KeyAllowed also feels right to me.

I am not sure I understand how to refactor this. My idea was that the typeConsumer object being created at the V7 layer and passed down to v8 code can bubble up the state (information if type was found) back to v7 layer. Allowing the code to take action (most of the time just deprecation warning) to be present in v7 layer.

The apply() method was meant to serve two functions. Retrieve and store the information for v7 layer if the type was found. And to tell v8 code that the key was allowed and exception when parsing is not necessary.

I also agree that side effect is probably unexpected. The TypeConsumer is visible as just a Function in v8 layer, so noone looking just at code which uses it would expect side effects.
If we have two classes, that would mean we would need to pass down two objects down to v8 layer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakelandis I think this is the main issue on that PR.
We can split this in two functions

  • KeyAllowed<String,Boolean> - a function returning true if a string is of allowed value (_type, types etc) false otherwise. This will then be pass down into a Request parsing logic - i.e. https://github.com/elastic/elasticsearch/blob/master/server/src/main/java/org/elasticsearch/action/termvectors/TermVectorsRequest.java#L588
  • second class - not sure about this one.. we need to go down from v7 rest layer to the same place where a request is parsed (v8 code).
    I understand that it is not obvious that a function would has a state. But from the parsing point of view it wouldn't matter. All it care in TermVectorsRequest.java#L588 is if the field is allowed. The state if the field occurred (type for that example) is only relevant in v7 code where a class can be used directly (not by the Function interface)

If we were to have a utility class it would have live within some common to all modules utility module. That would not be ideal I guess.
We could refactor hasTypes to be a utility that is consuming the function that was passed down. But I am not sure this would benefit much (except from solving the ordering)

Anyways I think I might be missing something in your idea of splitting this class into two. Can you please give more details?


@Override
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
request.param("type");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you plan another round of PRs to issue deprecation and compatibility warnings ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to include this in this PR too, so we could consider these API complete. Will revisit.

new Route(GET, "/{index}/_termvectors"),
new Route(POST, "/{index}/_termvectors"),
new Route(GET, "/{index}/_termvectors/{id}"),
new Route(POST, "/{index}/_termvectors/{id}"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the non-typed endpoints needed ?

Copy link
Contributor Author

@pgomulka pgomulka Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one also can expect a type in a body for all these paths (even non-typed) - hence it is using TypeConsumer (to be renamed).

}
readURIParameters(termVectorsRequest, request);

if (typeConsumer.hasTypes()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you move hasTypes a static method in a utility class, maybe we can push this logic (consume the type and log) there ?

new Route(GET, "/_msearch"),
new Route(POST, "/_msearch"),
new Route(GET, "/{index}/_msearch"),
new Route(POST, "/{index}/_msearch"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the non-typed end points needed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as per previous comments - type is present in a body

new Route(GET, "/_search"),
new Route(POST, "/_search"),
new Route(GET, "/{index}/_search"),
new Route(POST, "/{index}/_search"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-typed endpoints ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type can be present as a parameter in v7 (as well as in a path for typed endpoints)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although I am now not sure about INCLUDE_TYPE_NAME_PARAMETER
will revisit

new Route(GET, "/_msearch/template"),
new Route(POST, "/_msearch/template"),
new Route(GET, "/{index}/_msearch/template"),
new Route(POST, "/{index}/_msearch/template"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-typed endpoints ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again - type can be present in a body.

@pgomulka pgomulka changed the title WIP Compatible logic for Removes typed endpoint from search and related APIs Compatible logic for Removes typed endpoint from search and related APIs Apr 29, 2020
@pgomulka pgomulka marked this pull request as ready for review April 29, 2020 14:14
@pgomulka pgomulka removed the WIP label Apr 30, 2020
@rjernst rjernst added the Team:Core/Infra Meta label for core/infra team label May 4, 2020
@pgomulka pgomulka merged commit 2df6157 into elastic:compat_rest_api Jul 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/REST API REST infrastructure and utilities Team:Core/Infra Meta label for core/infra team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants