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 disabling default response rendering #3006

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
99 changes: 96 additions & 3 deletions docs/docs/mapping/customizing_openapi_output.md
Expand Up @@ -631,14 +631,107 @@ info:
title: helloproto/v1/example.proto
version: version not set
consumes:
- application/json
- application/json
produces:
- application/json
- application/json
paths:
/api/hello:
get:
operationId: EchoService_Hello
```

### Disable default responses

By default a 200 OK response is rendered for each service operation. But it is possible to disable this and explicitly define your service's responses, using the `disable_default_responses` option. Allowed values are: `true`, `false`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you just add a note somewhere to say that this does not change the behavior of the gateway itself, and must be coupled with a custom ForwardResponseWriter that adjusts the response to be an accurate reflection of the API behavior? Maybe link to the docs section that talks about changing the response 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.

Added a note @johanbrandhorst


**Note**: This does not alter the behavior of the gateway itself and should be coupled with a `ForwardResponseWriter` when altering status codes, see [Controlling HTTP Response Codes](https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/customizing_your_gateway/#controlling-http-response-status-codes).

For example, if you are using `buf`:

```yaml
version: v1
plugins:
- name: openapiv2
out: .
opt:
- disable_default_responses=true
```

or with `protoc`

```sh
protoc --openapiv2_out=. --openapiv2_opt=disable_default_responses=true ./path/to/file.proto
```

Input example:

```protobuf
syntax = "proto3";

package helloproto.v1;

import "google/api/annotations.proto";
import "protoc-gen-openapiv2/options/annotations.proto";

option go_package = "helloproto/v1;helloproto";

service EchoService {
rpc Hello(HelloReq) returns (HelloResp) {
option (google.api.http) = {get: "/api/hello"};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "201",
value: {
description: "Created";
schema: {
json_schema: {ref: ".helloproto.v1.HelloResp"}
}
}
};
};
}
}

message HelloReq {
string name = 1;
}

message HelloResp {
string message = 1;
}
```

Output (default response not generated):

```yaml
swagger: "2.0"
info:
title: helloproto/v1/hello.proto
version: version not set
consumes:
- application/json
produces:
- application/json
paths:
/api/hello:
get:
operationId: EchoService_Hello
...
responses:
"201":
description: Created
schema:
$ref: "#/definitions/v1HelloResp"
parameters:
- name: name
in: query
required: false
type: string
definitions:
v1HelloResp:
type: object
properties:
message:
type: string
```

{% endraw %}
14 changes: 14 additions & 0 deletions internal/descriptor/registry.go
Expand Up @@ -132,6 +132,10 @@ type Registry struct {
// disableServiceTags disables the generation of service tags.
// This is useful if you do not want to expose the names of your backend grpc services.
disableServiceTags bool

// disableDefaultResponses disables the generation of default responses.
// Useful if you have to support custom response codes that are not 200.
disableDefaultResponses bool
}

type repeatedFieldSeparator struct {
Expand Down Expand Up @@ -758,3 +762,13 @@ func (r *Registry) SetDisableServiceTags(use bool) {
func (r *Registry) GetDisableServiceTags() bool {
return r.disableServiceTags
}

// SetDisableDefaultResponses setsdisableDefaultResponses
func (r *Registry) SetDisableDefaultResponses(use bool) {
r.disableDefaultResponses = use
}

// GetDisableDefaultResponses returns disableDefaultResponses
func (r *Registry) GetDisableDefaultResponses() bool {
return r.disableDefaultResponses
}
16 changes: 9 additions & 7 deletions protoc-gen-openapiv2/internal/genopenapi/template.go
Expand Up @@ -1369,13 +1369,15 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re

operationObject := &openapiOperationObject{
Parameters: parameters,
Responses: openapiResponsesObject{
"200": openapiResponseObject{
Description: desc,
Schema: responseSchema,
Headers: openapiHeadersObject{},
},
},
Responses: openapiResponsesObject{},
}

if !reg.GetDisableDefaultResponses() {
operationObject.Responses["200"] = openapiResponseObject{
Description: desc,
Schema: responseSchema,
Headers: openapiHeadersObject{},
}
}

if !reg.GetDisableServiceTags() {
Expand Down
11 changes: 11 additions & 0 deletions protoc-gen-openapiv2/internal/genopenapi/template_test.go
Expand Up @@ -3316,6 +3316,17 @@ func TestApplyTemplateProtobufAny(t *testing.T) {
},
wantNumDefinitions: 3,
},
{
// we have a protobufAny in a message but with automatic rendering of responses disabled
name: "protobufAny_referenced_in_message_with_default_responses_disabled",
args: args{
msgContainsAny: true,
regConfig: func(reg *descriptor.Registry) {
reg.SetDisableDefaultResponses(true)
},
},
wantNumDefinitions: 4,
Comment on lines +3320 to +3328
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not exactly sure what this tests but it's here 😄

},
}

for _, tt := range tests {
Expand Down
2 changes: 2 additions & 0 deletions protoc-gen-openapiv2/main.go
Expand Up @@ -41,6 +41,7 @@ var (
outputFormat = flag.String("output_format", string(genopenapi.FormatJSON), fmt.Sprintf("output content format. Allowed values are: `%s`, `%s`", genopenapi.FormatJSON, genopenapi.FormatYAML))
visibilityRestrictionSelectors = utilities.StringArrayFlag(flag.CommandLine, "visibility_restriction_selectors", "list of `google.api.VisibilityRule` visibility labels to include in the generated output when a visibility annotation is defined. Repeat this option to supply multiple values. Elements without visibility annotations are unaffected by this setting.")
disableServiceTags = flag.Bool("disable_service_tags", false, "if set, disables generation of service tags. This is useful if you do not want to expose the names of your backend grpc services.")
disableDefaultResponses = flag.Bool("disable_default_responses", false, "if set, disables generation of default responses. Useful if you have to support custom response codes that are not 200.")
)

// Variables set by goreleaser at build time
Expand Down Expand Up @@ -126,6 +127,7 @@ func main() {
reg.SetOmitEnumDefaultValue(*omitEnumDefaultValue)
reg.SetVisibilityRestrictionSelectors(*visibilityRestrictionSelectors)
reg.SetDisableServiceTags(*disableServiceTags)
reg.SetDisableDefaultResponses(*disableDefaultResponses)
if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil {
emitError(err)
return
Expand Down