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

HTTP-78 Support for optional query parameters for body-based requests #79

Merged
merged 1 commit into from
Mar 22, 2024

Conversation

OlivierZembri
Copy link
Contributor

Support for optional query parameters for body-based requests

Description

As documented, the connector currently create a lookup query from the HTTP TableLookup Source to build either:

  • a query parameter list in case of a HTTP GET request
  • a body payload in case of a HTTP body-based request

There is no way to change this behaviour with custom factories.

Modification:

  • Change the signature of createLookupQuery(RowData lookupDataRow) in interface LookupQueryCreator so that it returns a class LookupQueryInfo holding:

    • the lookup query
    • the optional body-based query parameters
  • Adapt the creation of the URIs in the constructions of HTTP requests to retrieve information from the class LookupQueryInfo.

With these changes, any custom implementation of this interface that aims to provide body-based request is able to provide the lookup query as the payload and an optional formatted string representing the query parameters.

Resolves #78

PR Checklist

Copy link
Collaborator

@kristoffSC kristoffSC left a comment

Choose a reason for hiding this comment

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

Looking good but I have few nits and questions.

public LookupQueryInfo(String lookupQuery, Map<String, String> bodyBasedUrlQueryParams) {
this.lookupQuery =
Optional.ofNullable(lookupQuery)
.orElseGet(() -> "");
Copy link
Collaborator

Choose a reason for hiding this comment

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

you can use orElse("") instead orElseGet

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 your proposal is equivalent to what I wrote, there would be a performance penalty to use orElse("") instead orElseGet as explained here: https://www.baeldung.com/java-optional-or-else-vs-or-else-get#orElseGet

Choose a reason for hiding this comment

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

The link you've provided explains when orElse would introduce a performance penalty - that is, when you're calling a method inside the orElse() method, especially not straight forward one like random.
This performance hit comes because in case of orElse we're always calling that method, no matter if we need it or not. In case of orElseGet, we just call it when we actually need it. This is the only difference. Please refer to the implementation of both methods to confirm the above.
And so here, where a constant is used (see Java String Pool), there should be no performance difference whatsoever.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

.orElseGet(() -> "");
this.bodyBasedUrlQueryParams =
Optional.ofNullable(bodyBasedUrlQueryParams)
.orElseGet(() -> new LinkedHashMap<>());
Copy link
Collaborator

Choose a reason for hiding this comment

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

please consider using .orElse(Collections.emptyMap())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the same performance penalty mentioned in comment #79 (comment) would come into play

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but I understand your point to use a read-only collection with Collections.emptyMap()

Choose a reason for hiding this comment

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

Same as above - we're passing a constant here, there should be no difference in performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, the Collections.emptyMap() uses a static member compared to new LinkedHashMap<>()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

}

public String getBodyBasedUrlQueryParameters() {
return URLEncodedUtils.format(
Copy link
Collaborator

Choose a reason for hiding this comment

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

what would be returned if bodyBasedUrlQueryParams would be empty?
A null or empty string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An empty string is returned

if (lookupQueryInfo.hasBodyBasedUrlQueryParameters()) {
resolvedUrl.append(baseUrl.contains("?") ? "&" : "?")
.append(lookupQueryInfo.getBodyBasedUrlQueryParameters());
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm guessing you are planing to have your own LookupQueryCreator custom implementation that will return a LookupQueryInfo that will have both, query and body params right?

And you plan to use it with one of the HttpRequestFactory implementation right?

I wonder about contract between LookupQueryInfo and HttpRequestFactory.
In other words I wonder if the logic above is an implementation detail of LookupQueryInfo or public contract that LookupQueryInfo creator should know.

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'm guessing you are planing to have your own LookupQueryCreator custom implementation that will return a LookupQueryInfo that will have both, query and body params right?

Yes, that's the final purpose:

  • having POST requests with body parameters only
  • having POST requests with body parameters and query parameters

In other words I wonder if the logic above is an implementation detail of LookupQueryInfo

In my view, this is rather an implementation detail and the HttpRequestFactory can be left untouched thereby remaining the "happy path".

this.bodyBasedUrlQueryParams =
Optional.ofNullable(bodyBasedUrlQueryParams)
.orElse(Collections.emptyMap());
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually I don't think optional are the best thing to use here.
We are not gaining much from them and I would argue they are used not as Optionala were intend to be used.

I see that you are using them to have "nicely looking" null checks, but I think below code would do the same thing and will not be much harder do read:

this.lookupQuery = lookupQuery == null ? "" : lookupQuery;
this.bodyBasedUrlQueryParams = bodyBasedUrlQueryParams == null ? Collections.emptyMap() : bodyBasedUrlQueryParams;

Please substitute Optionals with the above code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Support for optional query parameters for body-based requests

Signed-off-by: Olivier Zembri <<ozembri@fr.ibm.com>>
@@ -53,9 +53,15 @@ protected Logger getLogger() {
return log;
}

private URI constructGetUri() {
URI constructBodyBasedUri(LookupQueryInfo lookupQueryInfo) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Small comment, I was confused by the name of this method. I wonder if constructUri or addQueryInfoToURI would be more appropriate.
When we add path parameters I assume there would be another map in LookupQueryInfo that we would use to replace content in the parameterised baseUrl.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When we add path parameters

This is not the scope of the current PR. It might be revisited with a PR dedicated to path parameters.

Copy link
Contributor

Choose a reason for hiding this comment

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

When we add path parameters

This is not the scope of the current PR. It might be revisited with a PR dedicated to path parameters.

OK

@kristoffSC kristoffSC merged commit b17ede3 into getindata:main Mar 22, 2024
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide optional query parameters along with the body payload.
4 participants