Skip to content

Commit a2ccb06

Browse files
committed
Protobuf Schema Support Multiple Response
1 parent bd9d93d commit a2ccb06

13 files changed

Lines changed: 257 additions & 42 deletions

File tree

bin/configs/protobuf-schema-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ additionalProperties:
88
numberedFieldNumberList: true
99
startEnumsWithUnspecified: true
1010
wrapComplexType: false
11+
supportMultipleResponses: true
1112
aggregateModelsName: data
1213
typeMappings:
1314
object: "google.protobuf.Struct"

docs/generators/protobuf-schema.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
2222
|aggregateModelsName|Aggregated model filename. If set, all generated models will be combined into this single file.| |null|
2323
|numberedFieldNumberList|Field numbers in order.| |false|
2424
|startEnumsWithUnspecified|Introduces "UNSPECIFIED" as the first element of enumerations.| |false|
25+
|supportMultipleResponses|Support multiple responses| |false|
2526
|wrapComplexType|Generate Additional message for complex type| |true|
2627

2728
## IMPORT MAPPING

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.openapitools.codegen.languages;
1818

1919
import io.swagger.v3.oas.models.OpenAPI;
20+
import io.swagger.v3.oas.models.PathItem;
2021
import io.swagger.v3.oas.models.media.ArraySchema;
2122
import io.swagger.v3.oas.models.media.MapSchema;
2223
import io.swagger.v3.oas.models.media.ObjectSchema;
@@ -68,6 +69,8 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
6869

6970
public static final String AGGREGATE_MODELS_NAME = "aggregateModelsName";
7071

72+
public static final String SUPPORT_MULTIPLE_RESPONSES = "supportMultipleResponses";
73+
7174
private final Logger LOGGER = LoggerFactory.getLogger(ProtobufSchemaCodegen.class);
7275

7376
@Setter protected String packageName = "openapitools";
@@ -82,6 +85,8 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
8285

8386
private boolean wrapComplexType = true;
8487

88+
private boolean supportMultipleResponses = false;
89+
8590
@Override
8691
public CodegenType getTag() {
8792
return CodegenType.SCHEMA;
@@ -192,6 +197,7 @@ public ProtobufSchemaCodegen() {
192197
addSwitch(START_ENUMS_WITH_UNSPECIFIED, "Introduces \"UNSPECIFIED\" as the first element of enumerations.", startEnumsWithUnspecified);
193198
addSwitch(ADD_JSON_NAME_ANNOTATION, "Append \"json_name\" annotation to message field when the specification name differs from the protobuf field name", addJsonNameAnnotation);
194199
addSwitch(WRAP_COMPLEX_TYPE, "Generate Additional message for complex type", wrapComplexType);
200+
addSwitch(SUPPORT_MULTIPLE_RESPONSES, "Support multiple responses", supportMultipleResponses);
195201
addOption(AGGREGATE_MODELS_NAME, "Aggregated model filename. If set, all generated models will be combined into this single file.", null);
196202
}
197203

@@ -239,6 +245,10 @@ public void processOpts() {
239245
this.setAggregateModelsName((String) additionalProperties.get(AGGREGATE_MODELS_NAME));
240246
}
241247

248+
if(additionalProperties.containsKey(this.SUPPORT_MULTIPLE_RESPONSES)) {
249+
this.supportMultipleResponses = convertPropertyToBooleanAndWriteBack(SUPPORT_MULTIPLE_RESPONSES);
250+
}
251+
242252
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
243253
}
244254

@@ -442,7 +452,6 @@ private void wrapModels() {
442452
} else if (ModelUtils.isAnyOf(schema)) {
443453
wrapComposedChildren(schema.getAnyOf(), visitedSchema);
444454
}
445-
446455
}
447456
}
448457

@@ -475,7 +484,6 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
475484
}
476485
}
477486

478-
479487
/**
480488
* Adds prefix to the enum allowable values
481489
* NOTE: Enum values use C++ scoping rules, meaning that enum values are siblings of their type, not children of it. Therefore, enum value must be unique
@@ -542,24 +550,28 @@ public void addEnumIndexes(List<Map<String, Object>> enumVars) {
542550

543551
public List<CodegenProperty> processOneOfAnyOfItems(List<CodegenProperty> composedSchemasProperty) {
544552
for(CodegenProperty cd: composedSchemasProperty) {
545-
if (cd.getTitle() != null) {
546-
cd.name = cd.getTitle();
547-
cd.baseName = cd.getTitle();
548-
} else{
549-
cd.name = getNameFromDataType(cd);
550-
cd.baseName = getNameFromDataType(cd);
551-
}
553+
cd.name = resolveVarName(cd);
554+
cd.baseName = resolveVarName(cd);
552555
}
553556
return composedSchemasProperty;
554557
}
555558

559+
560+
private String resolveVarName(CodegenProperty property) {
561+
if(property.getTitle() != null) {
562+
return toVarName(property.getTitle());
563+
} else {
564+
return getNameFromDataType(property);
565+
}
566+
}
567+
556568
public String getNameFromDataType(CodegenProperty property) {
557569
if (Boolean.TRUE.equals(property.getIsArray())){
558-
return underscore(property.mostInnerItems.dataType + ARRAY_SUFFIX);
570+
return toVarName(property.mostInnerItems.dataType + ARRAY_SUFFIX);
559571
} else if (Boolean.TRUE.equals(property.getIsMap())) {
560-
return underscore(property.mostInnerItems.dataType + MAP_SUFFIX);
572+
return toVarName(property.mostInnerItems.dataType + MAP_SUFFIX);
561573
} else {
562-
return underscore(property.dataType);
574+
return toVarName(property.dataType);
563575
}
564576
}
565577

@@ -944,6 +956,30 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
944956
}
945957
}
946958
}
959+
960+
if(this.supportMultipleResponses) {
961+
int responseIdx = 1;
962+
op.vendorExtensions.put("x-grpc-response", op.operationId+"Response");
963+
for (CodegenResponse r : op.responses) {
964+
if (r.returnProperty == null) {
965+
r.vendorExtensions.put("x-oneOf-response-type", "google.protobuf.Empty");
966+
r.vendorExtensions.put("x-oneOf-response-name", "empty");
967+
} else if (r.isMap) {
968+
r.vendorExtensions.put("x-oneOf-response-type", r.returnProperty.additionalProperties.dataType);
969+
r.vendorExtensions.put("x-oneOf-response-name", resolveVarName(r.returnProperty.additionalProperties));
970+
LOGGER.warn("Mapping responses for operations with supportMultipleResponses flag (operation ID: {}) is not currently supported.", op.operationId);
971+
} else if (r.isArray) {
972+
r.vendorExtensions.put("x-oneOf-response-type", r.returnProperty.items.dataType);
973+
r.vendorExtensions.put("x-oneOf-response-name", resolveVarName(r.returnProperty.items));
974+
LOGGER.warn("Array responses for operations with supportMultipleResponses flag (operation ID: {}) is not currently supported.", op.operationId);
975+
}
976+
else {
977+
r.vendorExtensions.put("x-oneOf-response-type", r.returnProperty.dataType);
978+
r.vendorExtensions.put("x-oneOf-response-name", resolveVarName(r.returnProperty));
979+
}
980+
r.vendorExtensions.put("x-oneOf-response-index", responseIdx++);
981+
}
982+
}
947983
}
948984

949985
if (this.aggregateModelsName != null) {

modules/openapi-generator/src/main/resources/protobuf-schema/api.mustache

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,14 @@ message {{operationId}}Response {
4242
}
4343

4444
{{/vendorExtensions.x-grpc-response}}
45+
{{#supportMultipleResponses}}
46+
message {{operationId}}Response {
47+
oneof response {
48+
{{#responses}}
49+
{{{vendorExtensions.x-oneOf-response-type}}} {{vendorExtensions.x-oneOf-response-name}}_{{code}} = {{vendorExtensions.x-oneOf-response-index}};
50+
{{/responses}}
51+
}
52+
}
53+
{{/supportMultipleResponses}}
4554
{{/operation}}
4655
{{/operations}}

modules/openapi-generator/src/test/resources/3_0/protobuf/petstore.yaml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ paths:
5959
schema:
6060
$ref: '#/components/schemas/Pet'
6161
'405':
62-
description: Invalid input
62+
$ref: '#/components/responses/ErrorResponse'
6363
security:
6464
- petstore_auth:
6565
- 'write:pets'
@@ -83,11 +83,11 @@ paths:
8383
schema:
8484
$ref: '#/components/schemas/Pet'
8585
'400':
86-
description: Invalid ID supplied
86+
$ref: '#/components/responses/ErrorResponse'
8787
'404':
88-
description: Pet not found
88+
$ref: '#/components/responses/ErrorResponse'
8989
'405':
90-
description: Validation exception
90+
$ref: '#/components/responses/ErrorResponse'
9191
security:
9292
- petstore_auth:
9393
- 'write:pets'
@@ -593,6 +593,13 @@ externalDocs:
593593
description: Find out more about Swagger
594594
url: 'http://swagger.io'
595595
components:
596+
responses:
597+
ErrorResponse:
598+
description: An error response.
599+
content:
600+
application/json:
601+
schema:
602+
$ref: '#/components/schemas/Error'
596603
requestBodies:
597604
UserArray:
598605
content:
@@ -786,3 +793,16 @@ components:
786793
uniqueItems: true
787794
items:
788795
type: string
796+
Error:
797+
type: object
798+
required:
799+
- code
800+
- message
801+
properties:
802+
code:
803+
type: integer
804+
format: int32
805+
description: Error code.
806+
message:
807+
type: string
808+
description: Detailed error message.

samples/config/petstore/protobuf-schema-config/models/data.proto

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ message Dog {
5656

5757
}
5858

59+
message Error {
60+
61+
// Error code.
62+
int32 code = 1;
63+
64+
// Detailed error message.
65+
string message = 2;
66+
67+
}
68+
5969
message Order {
6070

6171
int64 id = 1;

samples/config/petstore/protobuf-schema-config/services/default_service.proto

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import "google/protobuf/empty.proto";
1616
import public "models/data.proto";
1717

1818
service DefaultService {
19-
rpc PetsGet (PetsGetRequest) returns (google.protobuf.Empty);
19+
rpc PetsGet (PetsGetRequest) returns (PetsGetResponse);
2020

21-
rpc PetsPost (PetsPostRequest) returns (google.protobuf.Empty);
21+
rpc PetsPost (PetsPostRequest) returns (PetsPostResponse);
2222

2323
}
2424

@@ -27,8 +27,18 @@ message PetsGetRequest {
2727

2828
}
2929

30+
message PetsGetResponse {
31+
oneof response {
32+
google.protobuf.Empty empty_200 = 1;
33+
}
34+
}
3035
message PetsPostRequest {
3136
PetsPostRequest pets_post_request = 1;
3237

3338
}
3439

40+
message PetsPostResponse {
41+
oneof response {
42+
google.protobuf.Empty empty_200 = 1;
43+
}
44+
}

samples/config/petstore/protobuf-schema-config/services/pet_service.proto

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ import "google/protobuf/empty.proto";
1616
import public "models/data.proto";
1717

1818
service PetService {
19-
rpc AddPet (AddPetRequest) returns (Pet);
19+
rpc AddPet (AddPetRequest) returns (AddPetResponse);
2020

21-
rpc DeletePet (DeletePetRequest) returns (google.protobuf.Empty);
21+
rpc DeletePet (DeletePetRequest) returns (DeletePetResponse);
2222

2323
rpc FindPetsByStatus (FindPetsByStatusRequest) returns (FindPetsByStatusResponse);
2424

2525
rpc FindPetsByTags (FindPetsByTagsRequest) returns (FindPetsByTagsResponse);
2626

27-
rpc GetPetById (GetPetByIdRequest) returns (Pet);
27+
rpc GetPetById (GetPetByIdRequest) returns (GetPetByIdResponse);
2828

29-
rpc UpdatePet (UpdatePetRequest) returns (Pet);
29+
rpc UpdatePet (UpdatePetRequest) returns (UpdatePetResponse);
3030

31-
rpc UpdatePetWithForm (UpdatePetWithFormRequest) returns (google.protobuf.Empty);
31+
rpc UpdatePetWithForm (UpdatePetWithFormRequest) returns (UpdatePetWithFormResponse);
3232

33-
rpc UploadFile (UploadFileRequest) returns (ApiResponse);
33+
rpc UploadFile (UploadFileRequest) returns (UploadFileResponse);
3434

3535
}
3636

@@ -40,45 +40,75 @@ message AddPetRequest {
4040

4141
}
4242

43+
message AddPetResponse {
44+
oneof response {
45+
Pet pet_200 = 1;
46+
Error error_405 = 2;
47+
}
48+
}
4349
message DeletePetRequest {
4450
// Pet id to delete
4551
int64 pet_id = 1 [json_name="petId"];
4652
string api_key = 2;
4753

4854
}
4955

56+
message DeletePetResponse {
57+
oneof response {
58+
google.protobuf.Empty empty_400 = 1;
59+
}
60+
}
5061
message FindPetsByStatusRequest {
5162
// Status values that need to be considered for filter
5263
repeated string status = 1;
5364

5465
}
5566

5667
message FindPetsByStatusResponse {
57-
repeated Pet data = 1;
68+
oneof response {
69+
Pet pet_200 = 1;
70+
google.protobuf.Empty empty_400 = 2;
71+
}
5872
}
59-
6073
message FindPetsByTagsRequest {
6174
// Tags to filter by
6275
repeated string tags = 1;
6376

6477
}
6578

6679
message FindPetsByTagsResponse {
67-
repeated Pet data = 1;
80+
oneof response {
81+
Pet pet_200 = 1;
82+
google.protobuf.Empty empty_400 = 2;
83+
}
6884
}
69-
7085
message GetPetByIdRequest {
7186
// ID of pet to return
7287
int64 pet_id = 1 [json_name="petId"];
7388

7489
}
7590

91+
message GetPetByIdResponse {
92+
oneof response {
93+
Pet pet_200 = 1;
94+
google.protobuf.Empty empty_400 = 2;
95+
google.protobuf.Empty empty_404 = 3;
96+
}
97+
}
7698
message UpdatePetRequest {
7799
// Pet object that needs to be added to the store
78100
Pet pet = 1;
79101

80102
}
81103

104+
message UpdatePetResponse {
105+
oneof response {
106+
Pet pet_200 = 1;
107+
Error error_400 = 2;
108+
Error error_404 = 3;
109+
Error error_405 = 4;
110+
}
111+
}
82112
message UpdatePetWithFormRequest {
83113
// ID of pet that needs to be updated
84114
int64 pet_id = 1 [json_name="petId"];
@@ -89,6 +119,11 @@ message UpdatePetWithFormRequest {
89119

90120
}
91121

122+
message UpdatePetWithFormResponse {
123+
oneof response {
124+
google.protobuf.Empty empty_405 = 1;
125+
}
126+
}
92127
message UploadFileRequest {
93128
// ID of pet to update
94129
int64 pet_id = 1 [json_name="petId"];
@@ -99,3 +134,8 @@ message UploadFileRequest {
99134

100135
}
101136

137+
message UploadFileResponse {
138+
oneof response {
139+
ApiResponse api_response_200 = 1;
140+
}
141+
}

0 commit comments

Comments
 (0)