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

Support HttpRule with field response #712

Merged
merged 1 commit into from
Aug 17, 2018

Conversation

doroginin
Copy link
Contributor

@doroginin doroginin commented Jul 30, 2018

This PR adds support optional response_body field for google.api.HttpRule. Also see PR: googleapis/go-genproto#87 and googleapis/googleapis#512

This version of code can work with current HttpRule implementation and with forked implementation with new field. This implementation does not break existing code.

Also allow_repeated_fields_in_body flag added to make it possible using repeated fields in body and response_body. This flag can be used for slices in request and response.

Also flag json_name_in_swgdef added to make it possible to use Field.GetJsonName() instead of Field.GetName() for generating swagger definitions. See: #681 for more info.

@johanbrandhorst
Copy link
Collaborator

Ha, this seems to be exactly what @ivucica wanted in #707. Looking at https://github.com/googleapis/googleapis/blob/201d7be7f9da925df93bc52f8108963284f61aed/google/api/http.proto, this doesn't seem to be an official part of the http.proto file? Is this in the process of being merged? I don't think there's any chance of us supporting something that isn't part of the official spec.

@ivucica
Copy link
Collaborator

ivucica commented Jul 30, 2018

I have not yet received upstream response for #707.

I am opposed to merging this particular PR, as it may (cough cough) collide with upstream fields which are not publicly visible.

I am also opposed to forking google.api.HttpRule; if we want to introduce something like this, it should be a new option namespaced to gRPC-Gateway. (If upstream decides to support the equivalent field, we can switch at that point, but it should be close to what upstream supports.)

In that light, I suggest careful examination of what's currently present in google.api.HttpRule documentation, particularly look at response_body. I'd suggest comparing the comment that @doroginin put into his fork of http.proto which bears a resemblance to the documentation of certain fields missing from the public .proto file.

@ivucica
Copy link
Collaborator

ivucica commented Jul 30, 2018

This is improved, but if you do receive a response on googleapis/googleapis#512, I suspect it will be pushback.

I'm re-contacting upstream.

Copy link
Collaborator

@ivucica ivucica left a comment

Choose a reason for hiding this comment

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

  1. Please regenerate tests.

  2. Please consider the very, very probable outcome where you won't be able to merge the upstream google.api.HttpRule change -- can you reserve a new set of proto options in the option registry for grpc-gateway (in addition to the existing swagger-specific ones) and implement this using that?

    Let us know if you agree to update the PR like this and if you email the registry alias; otherwise I will do that in a day or two.

allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body")
grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format")
allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` field of `google.api.http` annotation")
useJSONNameInSwaggerDef = flag.Bool("json_name_in_swgdef", false, "if it sets Field.GetJsonName() will be used for generating swagger definitions, otherwise Field.GetName() will be used")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this flag only affecting the swagger definition? Won't this break the api generated with protoc-gen-grpc-gateway?

If this affects only protoc-gen-swagger, why is this a flag in protoc-gen-grpc-gateway?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, this flag should be in protoc-gen-swagger, i'll move it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. Please consider the very, very probable outcome where you won't be able to merge the upstream google.api.HttpRule change -- can you reserve a new set of proto options in the option registry for grpc-gateway (in addition to the existing swagger-specific ones) and implement this using that?

@ivucica do you mean implement option like this:

message AccountArray {
    repeated Account account = 1 [(grpc.gateway.options).unwrap_field = true]; // or promote_field?
}

I think it's less obvious solution than response_body field, and in this case you can't add additional bindings with different requests/responses mapping for example, how do you implement this with you solution?

service Strings {
    rpc ToUpper (String) returns (String) {
        option (google.api.http) = {
            post: "/strings/to_upper"
            body: "str"
            response_body: "str"
            additional_bindings: {
                post: "/strings/to_upper/v2",
                body: "*",
                response_body: "*",
            }
        };
    }
}

message String {
    repeated string str = 1;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

That was my original proposal, but I am fine with attaching it to rpc instead of message. We only need to move it to a proto field we actually control.

It is correct that you cannot add a different response_body with what I am proposing:

service Strings {
    rpc ToUpper (String) returns (String) {
        option (google.api.http) = {
            post: "/strings/to_upper"
            body: "str"
            additional_bindings: {
                post: "/strings/to_upper/v2",
                body: "*",
            }
        };
        option (grpc.gateway.rpc_options) = {
            response_body: "str"
        };
    }
}

That is indeed unfortunate, but I see additional_bindings as a bonus, and for the most part, I just use a 1:1 mapping.

Anything I can think of is ugly, including this possibly tolerable addition (which is not incompatible with what's above):

rpc ToUpper (String) returns (String) {
    option (google.api.http) = {
        post: "/strings/to_upper"
        body: "str"
        additional_bindings: {
            post: "/strings/to_upper/v2",
            body: "*",
        }
    };
    option (grpc.gateway.rpc_options) = {
        configure_rule: {
            rule: { post: "/strings/to_upper" }
            config: { response_body: "str" }
        }
        configure_rule: {
            rule: { post: "/strings/to_upper/v2" }
            config: { response_body: "*" }
        }
    };
}

To get what you want to happen, we do need to get upstream to release the response_body, which may be difficult.

Once again: I am nearly certain your .HttpRule PR will not be accepted, due to insights that I cannot detail here without approval. So, once again: you should explore alternative designs unless upstream decides to provide the field.

I strongly suspect grpc-gateway will not move to a forked google.api.HttpRule either (especially one that may long-term conflict with upstream developments).

Copy link
Collaborator

Choose a reason for hiding this comment

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

I propose we take design discussions into #707 instead of this particular PR?

@doroginin
Copy link
Contributor Author

@ivucica could you help with this failed job, please: https://travis-ci.org/grpc-ecosystem/grpc-gateway/jobs/410260132 ? What's wrong here?

@ivucica
Copy link
Collaborator

ivucica commented Jul 31, 2018

Some ongoing CI issues: #711 (comment)

I would not be worried and, were this PR otherwise mergable, I would not object to merging it.

@wora
Copy link
Contributor

wora commented Aug 1, 2018

Please document why this feature is needed. We intentionally keep gRPC transcoding extremely simple. The goal for gRPC transcoding is to build REST API from RPC API. We don't intend to be feature rich as OpenAPI. We generally don't need feature to build great and useful APIs. The less features, the better performance and quality.

@ivucica
Copy link
Collaborator

ivucica commented Aug 1, 2018

@wora See #707 for my own feature request. As I said there, some preexisting APIs, such as Mastodon's, cannot currently be described with google.api.HttpRule as they return a JSON list as a top level object. With this trivial change, they could be.

Without this change, when attempting to describe Mastodon's existing API, one would

  1. have to postprocess the JSON before returning it to the user,
  2. and also have to postprocess output of protoc-gen-swagger so it documents returning a list instead of a message

While that's somewhat tolerably doable, it's way hackier than just allowing users to specify which field should be the top level JSON entity.

Example endpoint that returns a list

I do believe designing APIs like so is a bad design, but that's better to be strongly discouraged in documentation and in the API Design Guide.

@doroginin might have another use.

@doroginin
Copy link
Contributor Author

@doroginin might have another use.

We use protoc-gen-swagger in https://github.com/utrack/clay project (in this project we generate http handlers from proto file and http client for them), also we generate swagger.json via protoc-gen-swagger.
In this pull request: utrack/clay#39 i added test which uses the feature from this pull request.
Here is the example of usage:
https://github.com/doroginin/clay/tree/871583110ffcbf9093c8aa429da1433557a4790e/integration/binding_with_body_and_response

@wora
Copy link
Contributor

wora commented Aug 2, 2018

I am publishing the change from upstream. It should land in a few days.

Copy link
Collaborator

@ivucica ivucica left a comment

Choose a reason for hiding this comment

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

Given this is now happening, per @wora's comment, we can discuss the technical and stylistic stuff in this PR, and then see to merging it once the .proto is updated upstream.

Thank you for your valuable contribution!


// useJSONNameInSwaggerDef if it true Field.GetJsonName() will be used for generating swagger definitions,
// otherwise Field.GetName() will be used
useJSONNameInSwaggerDef bool
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please rename this into useJSONNamesForFields and update the comment appropriately :-)

Separately, can you then make protoc-gen-grpc-gateway use the JSON names as well if the flag is set? If not, can you please add a TODO here for someone to take a stab at it. It would be long-term important that -swagger defines the same API that -grpc-gateway exposes.

r.useJSONNameInSwaggerDef = use
}

// GetUseJSONNameInSwaggerDef whether generation one swagger file out of multiple protos
Copy link
Collaborator

Choose a reason for hiding this comment

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

This comment is incorrect and nonsensical*, could you please fix it? :)

  • Its grammar is nonsensical even in IsAllowMerge, but here the comment itself is outright wrong.

@@ -318,6 +325,22 @@ func (r *Registry) SetMergeFileName(mergeFileName string) {
r.mergeFileName = mergeFileName
}

// SetAllowRepeatedFieldsInBody controls whether repeated field can be used in body field path
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given you are providing a getter for useJSONNameInSwaggerDef, did you mean to provide it for allowRepeatedFieldsInBody?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

getter added

@@ -227,10 +234,10 @@ func (p Parameter) ConvertFuncExpr() (string, error) {
return conv, nil
}

// Body describes a http requtest body to be sent to the method.
// Body describes a http request(response) body to be sent to the method(client).
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about the bash syntax:

// Body describes a http {request,response} body to be sent to the {method,client}.

or the regex syntax:

// Body describes a http (request|response) body to be sent to the (method|client).

Maybe expand the comment a bit, and mention this is used in body and response_body options in google.api.HttpRule?

@@ -625,6 +631,23 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re

methProtoPath := protoPathIndex(reflect.TypeOf((*pbdescriptor.ServiceDescriptorProto)(nil)), "Method")
desc := ""
var responseSchema swaggerSchemaObject

if b.Response == nil || len(b.Response.FieldPath) == 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a comment that this is resolving the value of response_body in the google.api.HttpRule

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@codecov-io
Copy link

codecov-io commented Aug 6, 2018

Codecov Report

Merging #712 into master will decrease coverage by 0.45%.
The diff coverage is 29.16%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #712      +/-   ##
==========================================
- Coverage   56.16%   55.71%   -0.46%     
==========================================
  Files          30       30              
  Lines        3112     3152      +40     
==========================================
+ Hits         1748     1756       +8     
- Misses       1193     1223      +30     
- Partials      171      173       +2
Impacted Files Coverage Δ
runtime/mux.go 44.16% <ø> (ø) ⬆️
protoc-gen-grpc-gateway/descriptor/types.go 49.07% <ø> (ø) ⬆️
protoc-gen-grpc-gateway/gengateway/template.go 55.76% <ø> (ø) ⬆️
runtime/handler.go 41.6% <0%> (-1.74%) ⬇️
protoc-gen-swagger/main.go 27.05% <0%> (-0.33%) ⬇️
protoc-gen-grpc-gateway/descriptor/registry.go 68.06% <0%> (-2.98%) ⬇️
protoc-gen-swagger/genswagger/template.go 38.36% <35%> (-0.4%) ⬇️
protoc-gen-grpc-gateway/descriptor/services.go 73.97% <53.84%> (-1.57%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bb916ca...b8fc556. Read the comment docs.

@doroginin
Copy link
Contributor Author

@ivucica
It's success! http.proto was updated in main repo: https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L303 👍
We just need to wait when this PR will be merged: googleapis/go-genproto#87

@doroginin
Copy link
Contributor Author

Now i'm preparing some tests for changes in this PR

@ivucica
Copy link
Collaborator

ivucica commented Aug 8, 2018

I previously asked:

Separately, can you then make protoc-gen-grpc-gateway use the JSON names as well if the flag is set? If not, can you please add a TODO here for someone to take a stab at it. It would be long-term important that -swagger defines the same API that -grpc-gateway exposes.

If you don't plan on updating protoc-gen-grpc-gateway to respect JSON names flag, could you at least add a TODO for someone else to do it? Thanks

@doroginin
Copy link
Contributor Author

Separately, can you then make protoc-gen-grpc-gateway use the JSON names as well if the flag is set? If not, can you please add a TODO here for someone to take a stab at it. It would be long-term important that -swagger defines the same API that -grpc-gateway exposes.

I think it's not needed. grpc-gateway uses json names or original name in request/response according with used marshaler which will created by user. So user can create marshaler as he wants and set corresponding option in protoc-gen-swagger for generating definition.

I added more comments about it for new flag.

@doroginin
Copy link
Contributor Author

@ivucica can you help to fix bazel test: https://travis-ci.org/grpc-ecosystem/grpc-gateway/jobs/414555020 ? I have never work with this stuff. We need to update version of google.golang.org/genproto to 383e8b2c3b9e36c4076b235b32537292176bae20 how can i do it?

// response, if it uses json tags for marshaling.
// Pay attention. By default grpc-gataway uses original proto name in responses. If you would like
// to use names from json tags change marshaller for gateway with runtime.ServeMuxOption
// runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: false})
Copy link
Collaborator

Choose a reason for hiding this comment

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

While this is helpful, I don't like the tone of this. How about:

// otherwise the original proto name is used. It's helpful for synchronizing the swagger definition with grpc-gateway
// response, if it uses json tags for marshaling.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

Gopkg.toml Outdated
@@ -51,7 +51,7 @@ required = [
[[constraint]]
# Also defined in bazelbuild/rules_go
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L131
revision = "86e600f69ee4704c6efbf6a2a40a5c10700e76c2"
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Will this change require a corresponding change to bazelbuild/rules_go?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see you already managed to confirm we will need this change.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you update this comment as well since this is no longer correct?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This comment still needs updating

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@johanbrandhorst
Copy link
Collaborator

@doroginin
Copy link
Contributor Author

@johanbrandhorst
we need at least this version of googleapis: googleapis/googleapis@3544ab1 (here is http.proto)
and this version of google.golang.org/genproto: googleapis/go-genproto@383e8b2 (here is http.pb.go)

@doroginin
Copy link
Contributor Author

Here i changed repositories.bzl: doroginin@f4300d0
But it is still not working: https://travis-ci.org/doroginin/grpc-gateway/jobs/414800225

@johanbrandhorst
Copy link
Collaborator

I'm not personally super familiar with Bazel so I don't know about that error, maybe @achew22 or @yugui can see what's left?

@johanbrandhorst
Copy link
Collaborator

Please squash the commits into a single commit with a nice descriptive commit message as well, in preparation for merge.

doroginin added a commit to doroginin/grpc-gateway that referenced this pull request Aug 12, 2018
…pc-ecosystem#712)

Also:
* add flag `allow_repeated_fields_in_body` in `protoc-gen-grpc-gateway`
* add flag `json_names_for_fields` in `protoc-gen-swagger`
doroginin added a commit to doroginin/grpc-gateway that referenced this pull request Aug 14, 2018
…pc-ecosystem#712)

Also:
* add flag `allow_repeated_fields_in_body` in `protoc-gen-grpc-gateway`
* add flag `json_names_for_fields` in `protoc-gen-swagger`
name = "org_golang_google_genproto",
commit = "383e8b2c3b9e36c4076b235b32537292176bae20",
importpath = "google.golang.org/genproto",
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, could you reference Gopkg.toml here as well? These two must be kept in sync, obviously.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Really these should all reference Gopkg.toml 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

…pc-ecosystem#712)

Also:
* add flag `allow_repeated_fields_in_body` in `protoc-gen-grpc-gateway`
* add flag `json_names_for_fields` in `protoc-gen-swagger`
@johanbrandhorst
Copy link
Collaborator

This LGTM, but I'll leave it for @ivucica to merge as he's more involved than I with this. Thanks for your contribution @doroginin!

@doroginin
Copy link
Contributor Author

Guys, any update here?
@ivucica we need your approve!

@johanbrandhorst
Copy link
Collaborator

@doroginin Thanks for your patience, I've reached out to Ivan, we'll try and get this merged as soon as possible :).

Copy link
Collaborator

@ivucica ivucica left a comment

Choose a reason for hiding this comment

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

LGTM!

I'll go ahead and merge this.

@ivucica ivucica merged commit e679739 into grpc-ecosystem:master Aug 17, 2018
ivucica referenced this pull request in googleapis/go-genproto Aug 17, 2018
* regenerate

* using latest protoc-gen-go
@ivucica
Copy link
Collaborator

ivucica commented Aug 17, 2018

Ouch. This will actually break people who don't use Gopkg.lock and just go get, like myself. This is because upstream google.golang.org/genproto merged @doroginin's 383e8b2c3b9e36c4076b235b32537292176bae20, but then steamrolled over the changes in googleapis/go-genproto@9739b9a

@johanbrandhorst Do you think we should rollback or roll forward?

@johanbrandhorst
Copy link
Collaborator

⚡ Can we roll forward? I'd prefer to get the right version ASAP.

@ivucica
Copy link
Collaborator

ivucica commented Aug 17, 2018

I'd like that too; I reopened the internal bug.

@bcdurden
Copy link

bcdurden commented Aug 17, 2018

Can we roll backwards? This just broke all of my builds that depend on this project. Unless the sync has yet to happen and that will fix this error:
go/src/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/services.go:146:49: opts.ResponseBody undefined (type *annotations.HttpRule has no field or method ResponseBody)

ivucica added a commit that referenced this pull request Aug 17, 2018
@johanbrandhorst
Copy link
Collaborator

@bcdurden Fair enough, we'll sort this asynchronously.

@bcdurden
Copy link

Much appreciated! I should have read upwards a bit before I commented anyhow 💯

@ivucica
Copy link
Collaborator

ivucica commented Aug 17, 2018

@bcdurden Upstream has already merged all the changes! Can you verify that your projects are no longer broken and that I can drop PR #730?

@bcdurden
Copy link

All good! Thanks for the quick turn-around!

@doroginin doroginin deleted the httprule-with-response branch August 20, 2018 07:54
@doroginin
Copy link
Contributor Author

Thank you for merging this, guys! Is there any plan to set tag for this version?

@doroginin
Copy link
Contributor Author

And let's restart the build on master branch, cause now it's errored!

@johanbrandhorst
Copy link
Collaborator

@doroginin See #733

adasari pushed a commit to adasari/grpc-gateway that referenced this pull request Apr 9, 2020
…pc-ecosystem#712)

Also:
* add flag `allow_repeated_fields_in_body` in `protoc-gen-grpc-gateway`
* add flag `json_names_for_fields` in `protoc-gen-swagger`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants