Sitelet https://github.com/googleapis/google-cloud-java/pull/14134
Skip to content

feat(gax): allow non-JSON HttpContent and absolute request URLs in HttpRequestRunnable - #14134

Open
whowes wants to merge 1 commit into
mainfrom
whowes/http-content-support
Open

feat(gax): allow non-JSON HttpContent and absolute request URLs in HttpRequestRunnable#14134
whowes wants to merge 1 commit into
mainfrom
whowes/http-content-support

Conversation

@whowes

@whowes whowes commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

GAX HTTP infrastructure currently assumes that

  • request content is always JSON
  • request URLs are always based on the client context associated with the service stub

This PR relaxes those assumptions to allow non-JSON content and arbitrary URLs, which will be needed for resumable upload support.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for non-JSON HTTP content and absolute URLs in HttpRequestRunnable. It adds a default getHttpContent method to HttpRequestFormatter to retrieve the request body as HttpContent, allowing custom content types like binary payloads. Additionally, HttpRequestRunnable is updated to handle absolute paths directly, bypassing endpoint normalization when the path starts with http:// or https://. Corresponding unit tests have been added to verify these changes. There are no review comments, and I have no additional feedback to provide.

@whowes whowes changed the title whowes/http content support feat(gax): allow non-JSON HttpContent and absolute request URLs in HttpRequestRunnable Aug 19, 2026
@whowes whowes changed the title feat(gax): allow non-JSON HttpContent and absolute request URLs in HttpRequestRunnable feat(gax): allow non-JSON HttpContent and absolute request URLs in HttpRequestRunnable Aug 20, 2026
@whowes
whowes force-pushed the whowes/http-content-support branch from 9199f0c to d65e70e Compare August 21, 2026 00:37
@whowes
whowes marked this pull request as ready for review August 21, 2026 21:56
@whowes
whowes requested review from a team as code owners August 21, 2026 21:56
@whowes
whowes requested a review from blakeli0 August 21, 2026 21:57
@whowes
whowes force-pushed the whowes/http-content-support branch from d65e70e to 41307c2 Compare August 24, 2026 19:40
* #getRequestBody(Object)} to JSON, or {@link EmptyContent} if the body is empty.
*/
@BetaApi
default HttpContent getHttpContent(MessageFormatT apiMessage) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we expect this method to be used by classes other than HttpRequestRunnable? If not, I would prefer it to be a private helper method in HttpRequestRunnable instead of a public method in this interface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The only caller is expected to be HttpRequestRunnable, but the point of this being a method on the formatter interface is for formatters that process binary message bodies (e.g. for chunk uploads) to be able to override this to be not-JSON. See e.g. in the unit test for this functionality.

If this JSON implementation were a private helper in HttpRequestRunnable then IIUC the special case logic for the binary case would have to live there as well (e.g. switching behavior based on instanceof the request). IMO it's cleaner for any special casing required for a particular formatter to live in that formatter. I can play around with alternative ways to express that differently if you feel strongly though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I reverted the change to the public interface after offline discussion. I still prefer to have the special-case behavior for binary content outside of the HttpRequestRunnable and in the associated formatter implementation instead, so I defined a separate package-private interface for formatters that handle binary to implement. LMK what you think about this approach.

GenericUrl url = new Genericurl(/sitelet?url=https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fgoogle-cloud-java%2Fpull%2FnormalizedEndpoint%2520%2B%2520requestFormatter.getPath%28request));
String path = requestFormatter.getPath(request);
GenericUrl url;
if (path.startsWith("http://") || path.startsWith("https://")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this for the upload URL that is returned from the start request?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's the use case for this.

@whowes
whowes force-pushed the whowes/http-content-support branch 2 times, most recently from 0722994 to 3a870a0 Compare August 25, 2026 21:44
@whowes
whowes force-pushed the whowes/http-content-support branch from 3a870a0 to 7de9fde Compare August 25, 2026 22:00
@whowes

whowes commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the HttpContentRequestFormatter interface to support requests with arbitrary HttpContent payloads (such as raw bytes or streams) instead of serialized JSON strings. It also updates HttpRequestRunnable to handle these non-JSON payloads and support absolute URLs directly from the request formatter. A high-severity issue was identified where the new HttpContentRequestFormatter interface is package-private, which prevents it from being implemented by external classes or generated client stubs; it should be declared public.

* streams) rather than serialized JSON strings.
*/
@NullMarked
interface HttpContentRequestFormatter<MessageFormatT> extends HttpRequestFormatter<MessageFormatT> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The HttpContentRequestFormatter interface is currently package-private. Since HttpRequestFormatter is a public interface implemented by generated client stubs and other classes outside of the com.google.api.gax.httpjson package, this interface must be declared public so that it can be implemented by external classes (e.g., for resumable uploads in other packages).

Suggested change
interface HttpContentRequestFormatter<MessageFormatT> extends HttpRequestFormatter<MessageFormatT> {
public interface HttpContentRequestFormatter<MessageFormatT> extends HttpRequestFormatter<MessageFormatT> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is intentionally package private, as implementing classes are intended to live only in this package.

@sonarqubecloud

Copy link
Copy Markdown

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed for 'gapic-generator-java-root'

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@whowes
whowes requested a review from blakeli0 August 25, 2026 22:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants