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

Handle google.api.HttpBody? #344

Closed
broady opened this issue Mar 19, 2019 · 9 comments
Closed

Handle google.api.HttpBody? #344

broady opened this issue Mar 19, 2019 · 9 comments
Assignees
Labels
type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@broady
Copy link
Contributor

broady commented Mar 19, 2019

Looks like this was handled specifically for ML engine in #241 (CL 34871) but maybe not for the general case.

For example, healthcare.Projects.Locations.Datasets.FhirStores.Fhir.CreateResource, which accepts raw JSON.

We currently re-encode the JSON and force a bunch of stuff on the user.

Do we know of any API where HttpBody in a request actually works? If not, I propose we apply the ML engine patch to any outgoing request using the HttpBody type.

/cc @jadekler @noahdietz @jba

@jeanbza
Copy link
Member

jeanbza commented Mar 19, 2019

Augmenting this post-conversation for posterity:

Do we know of any API where HttpBody in a request actually works?

ML, per https://code-review.googlesource.com/c/34871.


My understanding of this FR

Given a discovery doc like the following: https://ml.googleapis.com/$discovery/rest?version=v1, we should look for things like,

          "response": {
            "$ref": "GoogleApi__HttpBody"
          },

And when we see GoogleApi__HttpBody we should skip the JSON decoding step. We did this in cl34871 but the signal is the specific method name - this request asks us to generalize.

@jeanbza jeanbza added the type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. label Mar 19, 2019
@broady
Copy link
Contributor Author

broady commented Mar 19, 2019

Sorry, yes, I meant other than the ML APIs.

Yeah, I think we need to handle HttpBody for return values, too.

CL 34871 is missing a couple things. It ignores ContentType, which are important for the healthcare API, at least - maybe others.

It also treats Body's string type as an alias to []byte, which is problematic because of #346, creating an inconsistency with how it's handled in other parts of the surface.

Two options (there's probably more):

  • apply CL 34871's strategy to all HttpBody, add ContentType. For responses, unpack the http.Response into the HttpBody struct.
  • think about whether we want to expose more things on *http.Request, and forego generating the HttpBody struct entirely. And handle HttpBody responses in a similar way.

@broady
Copy link
Contributor Author

broady commented Mar 25, 2019

Looks like only healthcare and ml use HttpBody.

For some reason, ML ends up with a type name of GoogleApi__HttpBody, and healthcare as simply HttpBody.

ML API has HttpBody as a field in GoogleCloudMlV1__PredictRequest

Healthcare API has HttpBody as a function parameter in CreateResource

See internal bug 38043930 for more detail on discovery generation problems with HttpBody.

@broady
Copy link
Contributor Author

broady commented Mar 25, 2019

The following is maybe only for healthcare, since it has so many raw HTTP operations...

I'm leaning towards adding a top-level helper to Service:

func (s *Service) DoHTTP(method, path string, body io.Reader) (*http.Response, error)

This would essentially pass through to the underlying http.Client, also prefixing Service.BasePath to the provided path.

Then, for any method that asks for (or returns) an HttpBody, document that people should use DoHTTP instead.

Other names to bikeshed:
Do, DoRaw
Get/Post/Patch/Delete (like http.Client)

@tbpg
Copy link
Contributor

tbpg commented Mar 25, 2019

Should we change the API (make it easier to use than work around it)?

I agree this would be OK to do for just Healthcare - not a widespread issue.

I'm good with any of the names. I like "HTTP" because it connects with HttpBody. I like "raw" because it implies it's not nicely typed.

@lukesneeringer
Copy link

Should we change the API (make it easier to use than work around it)?

Healthcare needs to return google.api.HttpBody. The basic reason is that the API conforms to a very specific external standard in the medical industry. (I do not think what it returns is even JSON; I think it is XML conforming to a specific schema.)

@broady
Copy link
Contributor Author

broady commented Mar 26, 2019

Figured out a more elegant way to handle this.

Please review over on CL 39310.

Code looks like this to use:

call := fhirService.CreateResource(parent, resourceType, bytes.NewReader(jsonPayload))
call.Header().Set("Content-Type", "application/fhir+json;charset=utf-8")
resp, err := call.Do()
if err != nil {
	return fmt.Errorf("CreateResource: %v", err)
}
defer resp.Body.Close()

This is quite a bit better than requiring users construct their own *http.Request, because they get type safety on the correct method and URL path parameters via the discovery service.

This means you only get access to change the body and any headers. We can add more stuff later if we need to.

@broady broady self-assigned this Mar 26, 2019
gopherbot pushed a commit that referenced this issue Apr 30, 2019
This takes a different approach than the changes made for the ML API
(see #241). Healthcare and ML API, strangely, have different formats for
HttpBody. They are the only two APIs currently using HttpBody.

This change makes any HttpBody call accept an io.Reader, which is used
as the HTTP request's Body. Headers can be added using the existing
Header() function on the Call. Additional headers and parameters are not
added, nor is any processing done on the response.

This is quite a bit better than requiring users construct their own
*http.Request, because they get type safety on the correct method and
URL path parameters via the discovery service.

Updates #344.

Code looks like this to use:

	call := fhirService.CreateResource(parent, resourceType, bytes.NewReader(jsonPayload))
	call.Header().Set("Content-Type", "application/fhir+json;charset=utf-8")
	resp, err := call.Do()
	if err != nil {
		return fmt.Errorf("CreateResource: %v", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode > 299 {
		return fmt.Errorf("CreateResource: status %d %s", resp.StatusCode, resp.Status)
	}

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("Could not read response: %v", err)
	}

Change-Id: I87cbf7535fbdeacf8cf74ba4ead82ecbd9f187f8
Reviewed-on: https://code-review.googlesource.com/c/google-api-go-client/+/39310
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Tyler Bui-Palsulich <tbp@google.com>
Reviewed-by: Jean de Klerk <deklerk@google.com>
@codyoss
Copy link
Member

codyoss commented Apr 14, 2020

@broady It looks like this could be closed, or is there still more work to do here?

@codyoss codyoss assigned codyoss and unassigned broady Jun 30, 2022
@codyoss
Copy link
Member

codyoss commented Jun 30, 2022

This looks to be solved for the APIs that we cared about. As there has not been much traction on this bug over the three years I think it is good enough to close this for now. We can re-evaluate individual cases should the need arise.

@codyoss codyoss closed this as completed Jun 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

5 participants