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

protoc-gen-openapiv2: support overriding path parameter names #2562

Merged
merged 9 commits into from
Mar 21, 2022
46 changes: 46 additions & 0 deletions docs/docs/mapping/customizing_openapi_output.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,52 @@ For a more in depth example see [visibility_rule_echo_service.proto](https://git
- [`visibility_restriction_selectors=INTERNAL,visibility_restriction_selectors=PREVIEW`](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/visibility_rule_preview_and_internal_echo_service.swagger.json)
- [Not set](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/visibility_rule_none_echo_service.swagger.json)

### Path parameters

When defining HTTP bindings with path parameters that contain multiple path segments, as suggested by the [Google AIPs](https://google.aip.dev/), the path parameter names are numbered to avoid generating duplicate paths in the OpenAPI file.

For example, consider:
```protobuf
service LibraryService {
rpc GetShelf(GetShelfRequest) returns (Shelf) {
option (google.api.http) = {
get: "/v1/{name=shelves/*}"
};
}
rpc GetBook(GetBookRequest) returns (Book) {
option (google.api.http) = {
get: "/v1/{name=shelves/*/books/*}"
};
}
}

message GetShelfRequest {
string name = 1;
}

message GetBookRequest {
string name = 1;
}
```

This will generate the following paths:
- `/v1/{name}`
- `/v1/{name_1}`

To override the path parameter names, annotate the field used as path parameter:
```protobuf
message GetShelfRequest {
string name = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {field_configuration: {path_param_name: "shelfName"}}];
}
message GetBookRequest {
string name = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {field_configuration: {path_param_name: "bookName"}}];
}
```

This will instead generate the following paths:
- `/v1/{shelfName}`
- `/v1/{bookName}`

### Output format

By default the output format is JSON, but it is possible to configure it using the `output_format` option. Allowed values are: `json`, `yaml`. The output format will also change the extension of the output files.
Expand Down
55 changes: 28 additions & 27 deletions examples/internal/clients/abe/api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1059,17 +1059,17 @@ paths:
description: "An unexpected error response."
schema:
$ref: "#/definitions/rpcStatus"
/v1/example/a_bit_of_everything/query/{uuid}:
/v1/example/a_bit_of_everything/query/{uuidName}:
get:
tags:
- "ABitOfEverythingService"
operationId: "ABitOfEverythingService_GetQuery"
parameters:
- name: "uuid"
- name: "uuidName"
in: "path"
required: true
type: "string"
x-exportParamName: "Uuid"
x-exportParamName: "UuidName"
- name: "singleNested.name"
in: "query"
description: "name is nested field."
Expand Down Expand Up @@ -1692,22 +1692,27 @@ paths:
description: "An unexpected error response."
schema:
$ref: "#/definitions/rpcStatus"
/v1/example/a_bit_of_everything/{uuid}:
get:
/v1/example/a_bit_of_everything/{uuidName}:
put:
tags:
- "ABitOfEverythingService"
operationId: "ABitOfEverythingService_Lookup"
operationId: "ABitOfEverythingService_Update"
parameters:
- name: "uuid"
- name: "uuidName"
in: "path"
required: true
type: "string"
x-exportParamName: "Uuid"
x-exportParamName: "UuidName"
- in: "body"
name: "body"
required: true
schema:
$ref: "#/definitions/A bit of everything"
x-exportParamName: "Body"
responses:
200:
description: "A successful response."
schema:
$ref: "#/definitions/examplepbABitOfEverything"
schema: {}
403:
description: "Returned when the user does not have permission to access\
\ the resource."
Expand All @@ -1729,26 +1734,22 @@ paths:
description: "An unexpected error response."
schema:
$ref: "#/definitions/rpcStatus"
put:
/v1/example/a_bit_of_everything/{uuid}:
get:
tags:
- "ABitOfEverythingService"
operationId: "ABitOfEverythingService_Update"
operationId: "ABitOfEverythingService_Lookup"
parameters:
- name: "uuid"
in: "path"
required: true
type: "string"
x-exportParamName: "Uuid"
- in: "body"
name: "body"
required: true
schema:
$ref: "#/definitions/A bit of everything"
x-exportParamName: "Body"
responses:
200:
description: "A successful response."
schema: {}
schema:
$ref: "#/definitions/examplepbABitOfEverything"
403:
description: "Returned when the user does not have permission to access\
\ the resource."
Expand Down Expand Up @@ -2200,17 +2201,17 @@ paths:
description: "An unexpected error response."
schema:
$ref: "#/definitions/rpcStatus"
/v2/example/a_bit_of_everything/{abe.uuid}:
/v2/example/a_bit_of_everything/{uuidName}:
put:
tags:
- "ABitOfEverythingService"
operationId: "ABitOfEverythingService_UpdateV2"
parameters:
- name: "abe.uuid"
- name: "uuidName"
in: "path"
required: true
type: "string"
x-exportParamName: "AbeUuid"
x-exportParamName: "UuidName"
- in: "body"
name: "abe"
description: "A bit of everything\n\nIntentionally complicated message type\
Expand Down Expand Up @@ -2256,11 +2257,11 @@ paths:
- "ABitOfEverythingService"
operationId: "ABitOfEverythingService_UpdateV22"
parameters:
- name: "abe.uuid"
- name: "uuidName"
in: "path"
required: true
type: "string"
x-exportParamName: "AbeUuid"
x-exportParamName: "UuidName"
- in: "body"
name: "abe"
description: "A bit of everything\n\nIntentionally complicated message type\
Expand Down Expand Up @@ -2650,17 +2651,17 @@ paths:
description: "An unexpected error response."
schema:
$ref: "#/definitions/rpcStatus"
/v2a/example/a_bit_of_everything/{abe.uuid}:
/v2a/example/a_bit_of_everything/{uuidName}:
patch:
tags:
- "ABitOfEverythingService"
operationId: "ABitOfEverythingService_UpdateV23"
parameters:
- name: "abe.uuid"
- name: "uuidName"
in: "path"
required: true
type: "string"
x-exportParamName: "AbeUuid"
x-exportParamName: "UuidName"
- in: "body"
name: "body"
required: true
Expand Down
40 changes: 20 additions & 20 deletions examples/internal/clients/abe/api_a_bit_of_everything_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2718,7 +2718,7 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceGetMessageWit
/*
ABitOfEverythingServiceApiService
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @param uuid
* @param uuidName
* @param floatValue Float value field
* @param requiredStringViaFieldBehaviorAnnotation mark a field as required in Open API definition
* @param optional nil or *ABitOfEverythingServiceGetQueryOpts - Optional Parameters:
Expand Down Expand Up @@ -2797,7 +2797,7 @@ type ABitOfEverythingServiceGetQueryOpts struct {
OptionalStringValue optional.String
}

func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceGetQuery(ctx context.Context, uuid string, floatValue float32, requiredStringViaFieldBehaviorAnnotation string, localVarOptionals *ABitOfEverythingServiceGetQueryOpts) (interface{}, *http.Response, error) {
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceGetQuery(ctx context.Context, uuidName string, floatValue float32, requiredStringViaFieldBehaviorAnnotation string, localVarOptionals *ABitOfEverythingServiceGetQueryOpts) (interface{}, *http.Response, error) {
var (
localVarHttpMethod = strings.ToUpper("Get")
localVarPostBody interface{}
Expand All @@ -2807,8 +2807,8 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceGetQuery(ctx
)

// create path and map variables
localVarPath := a.client.cfg.BasePath + "/v1/example/a_bit_of_everything/query/{uuid}"
localVarPath = strings.Replace(localVarPath, "{"+"uuid"+"}", fmt.Sprintf("%v", uuid), -1)
localVarPath := a.client.cfg.BasePath + "/v1/example/a_bit_of_everything/query/{uuidName}"
localVarPath = strings.Replace(localVarPath, "{"+"uuidName"+"}", fmt.Sprintf("%v", uuidName), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
Expand Down Expand Up @@ -3897,12 +3897,12 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceTimeout(ctx c
/*
ABitOfEverythingServiceApiService
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @param uuid
* @param uuidName
* @param body

@return interface{}
*/
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdate(ctx context.Context, uuid string, body ABitOfEverything) (interface{}, *http.Response, error) {
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdate(ctx context.Context, uuidName string, body ABitOfEverything) (interface{}, *http.Response, error) {
var (
localVarHttpMethod = strings.ToUpper("Put")
localVarPostBody interface{}
Expand All @@ -3912,8 +3912,8 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdate(ctx co
)

// create path and map variables
localVarPath := a.client.cfg.BasePath + "/v1/example/a_bit_of_everything/{uuid}"
localVarPath = strings.Replace(localVarPath, "{"+"uuid"+"}", fmt.Sprintf("%v", uuid), -1)
localVarPath := a.client.cfg.BasePath + "/v1/example/a_bit_of_everything/{uuidName}"
localVarPath = strings.Replace(localVarPath, "{"+"uuidName"+"}", fmt.Sprintf("%v", uuidName), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
Expand Down Expand Up @@ -4230,7 +4230,7 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateBook(ct
/*
ABitOfEverythingServiceApiService
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @param abeUuid
* @param uuidName
* @param abe A bit of everything Intentionally complicated message type to cover many features of Protobuf.
* @param optional nil or *ABitOfEverythingServiceUpdateV2Opts - Optional Parameters:
* @param "UpdateMask" (optional.String) - The paths to update.
Expand All @@ -4242,7 +4242,7 @@ type ABitOfEverythingServiceUpdateV2Opts struct {
UpdateMask optional.String
}

func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV2(ctx context.Context, abeUuid string, abe ABitOfEverything2, localVarOptionals *ABitOfEverythingServiceUpdateV2Opts) (interface{}, *http.Response, error) {
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV2(ctx context.Context, uuidName string, abe ABitOfEverything2, localVarOptionals *ABitOfEverythingServiceUpdateV2Opts) (interface{}, *http.Response, error) {
var (
localVarHttpMethod = strings.ToUpper("Put")
localVarPostBody interface{}
Expand All @@ -4252,8 +4252,8 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV2(ctx
)

// create path and map variables
localVarPath := a.client.cfg.BasePath + "/v2/example/a_bit_of_everything/{abe.uuid}"
localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1)
localVarPath := a.client.cfg.BasePath + "/v2/example/a_bit_of_everything/{uuidName}"
localVarPath = strings.Replace(localVarPath, "{"+"uuidName"+"}", fmt.Sprintf("%v", uuidName), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
Expand Down Expand Up @@ -4399,7 +4399,7 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV2(ctx
/*
ABitOfEverythingServiceApiService
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @param abeUuid
* @param uuidName
* @param abe A bit of everything Intentionally complicated message type to cover many features of Protobuf.
* @param optional nil or *ABitOfEverythingServiceUpdateV22Opts - Optional Parameters:
* @param "UpdateMask" (optional.String) - The paths to update.
Expand All @@ -4411,7 +4411,7 @@ type ABitOfEverythingServiceUpdateV22Opts struct {
UpdateMask optional.String
}

func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV22(ctx context.Context, abeUuid string, abe ABitOfEverything3, localVarOptionals *ABitOfEverythingServiceUpdateV22Opts) (interface{}, *http.Response, error) {
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV22(ctx context.Context, uuidName string, abe ABitOfEverything3, localVarOptionals *ABitOfEverythingServiceUpdateV22Opts) (interface{}, *http.Response, error) {
var (
localVarHttpMethod = strings.ToUpper("Patch")
localVarPostBody interface{}
Expand All @@ -4421,8 +4421,8 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV22(ctx
)

// create path and map variables
localVarPath := a.client.cfg.BasePath + "/v2/example/a_bit_of_everything/{abe.uuid}"
localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1)
localVarPath := a.client.cfg.BasePath + "/v2/example/a_bit_of_everything/{uuidName}"
localVarPath = strings.Replace(localVarPath, "{"+"uuidName"+"}", fmt.Sprintf("%v", uuidName), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
Expand Down Expand Up @@ -4568,12 +4568,12 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV22(ctx
/*
ABitOfEverythingServiceApiService
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @param abeUuid
* @param uuidName
* @param body

@return interface{}
*/
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV23(ctx context.Context, abeUuid string, body UpdateV2RequestRequestForUpdateIncludesTheMessageAndTheUpdateMask) (interface{}, *http.Response, error) {
func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV23(ctx context.Context, uuidName string, body UpdateV2RequestRequestForUpdateIncludesTheMessageAndTheUpdateMask) (interface{}, *http.Response, error) {
var (
localVarHttpMethod = strings.ToUpper("Patch")
localVarPostBody interface{}
Expand All @@ -4583,8 +4583,8 @@ func (a *ABitOfEverythingServiceApiService) ABitOfEverythingServiceUpdateV23(ctx
)

// create path and map variables
localVarPath := a.client.cfg.BasePath + "/v2a/example/a_bit_of_everything/{abe.uuid}"
localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1)
localVarPath := a.client.cfg.BasePath + "/v2a/example/a_bit_of_everything/{uuidName}"
localVarPath = strings.Replace(localVarPath, "{"+"uuidName"+"}", fmt.Sprintf("%v", uuidName), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
Expand Down
Loading