Skip to content

Commit 3fcb164

Browse files
authored
Refactor oneOf variants in schema components (#7)
1 parent 166631c commit 3fcb164

File tree

10 files changed

+976
-610
lines changed

10 files changed

+976
-610
lines changed

golden-file-tests/apidocs_golden.swagger.json

Lines changed: 335 additions & 148 deletions
Large diffs are not rendered by default.

golden-file-tests/apidocs_golden_preview_visibility.swagger.json

Lines changed: 350 additions & 193 deletions
Large diffs are not rendered by default.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Directory containing the protobuf files
2+
mkdir -p proto
3+
cp -a src/** proto/
4+
cp -a deps/** proto/
5+
proto_dir="proto"
6+
go_out_dir="internal"
7+
mod_prefix="github.com/coralogix"
8+
mod_name="$mod_prefix/openapi-facade/go"
9+
proto_files=($(find "$proto_dir" -name "*.proto" -print))
10+
openapi_args=""
11+
12+
# Build arguments for import paths of all modules
13+
for proto_file in "${proto_files[@]}"
14+
do
15+
out_module=$(dirname $proto_file)
16+
17+
if [[ $out_module == *"coralogix"* ]]; then
18+
mod_path="${out_module##*/com/}"
19+
# For all other protos, the package path is the same as the directory path
20+
openapi_args+="--openapiv3_opt=M${proto_file##*$proto_dir/}=${mod_name}/${go_out_dir}/${mod_path} "
21+
fi
22+
done
23+
24+
protofile_list=""
25+
26+
for proto_file in "${proto_files[@]}"
27+
do
28+
protofile_list+="${proto_file} "
29+
done
30+
31+
protoc --proto_path=$proto_dir --openapiv3_out=.. --openapiv3_opt=allow_merge=true,ignore_additional_bindings=true,openapi_naming_strategy=simple,visibility_restriction_selectors=PREVIEW $openapi_args $protofile_list

golden-file-tests/cx-api/output.txt

Whitespace-only changes.

golden-file-tests/cx-api/src/com/coralogixapis/thing/v1/thing.proto

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,25 @@ message Thing {
1919
optional google.protobuf.Timestamp created_at = 4 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"2021-01-01T00:00:00Z\""}];
2020
NestedStruct nested_field = 5;
2121
string preview_field = 6 [(google.api.field_visibility).restriction = "PREVIEW"];
22+
ThingType thing_type = 7 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"THING_TYPE_STANDARD\""}];
23+
oneof polymorphic_field {
24+
PolymorphicVariantA variant_a = 8;
25+
PolymorphicVariantB variant_b = 9;
26+
}
2227
}
2328

2429
message NestedStruct {
2530
int32 numeric_field = 1;
2631
string string_field = 2;
2732
}
2833

34+
message PolymorphicVariantA {
35+
string field_a = 1;
36+
}
2937

38+
message PolymorphicVariantB {
39+
int32 field_b = 1;
40+
}
3041

3142
enum ThingType {
3243
option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_enum) = {

golden-file-tests/cx-api/src/com/coralogixapis/thing/v1/thing_service.proto

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "com/coralogixapis/thing/v1/thing.proto";
66
import "google/api/annotations.proto";
77
import "google/api/http.proto";
88
import "google/api/visibility.proto";
9+
import "google/protobuf/timestamp.proto";
910
import "protoc-gen-openapiv3/options/annotations.proto";
1011

1112
// ThingService is the service for managing things.
@@ -18,8 +19,8 @@ service ThingService {
1819
// RPC for creating a thing.
1920
rpc CreateThing(CreateThingRequest) returns (CreateThingResponse) {
2021
option (google.api.http) = {
21-
post: "/v1/things/{thing.nested_field.numeric_field}"
22-
body: "thing.name"
22+
post: "/v1/things"
23+
body: "*"
2324
};
2425

2526
option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_operation) = {
@@ -44,7 +45,7 @@ service ThingService {
4445
rpc PreviewMethod(CreateThingRequest) returns (CreateThingResponse) {
4546
option (google.api.http) = {
4647
post: "/v1/things/preview"
47-
body: "thing.name"
48+
body: "*"
4849
};
4950
option (google.api.method_visibility).restriction = "PREVIEW";
5051

@@ -71,8 +72,8 @@ service ThingService {
7172
// RPC for replacing a thing.
7273
rpc ReplaceThing(ReplaceThingRequest) returns (ReplaceThingResponse) {
7374
option (google.api.http) = {
74-
put: "/v1/things/{thing.id}"
75-
body: "*"
75+
put: "/v1/things/{thing_id}"
76+
body: "thing"
7677
};
7778

7879
option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_operation) = {
@@ -139,7 +140,7 @@ service ThingService {
139140

140141
// RPC for listing things with pagination.
141142
rpc ListThings(ListThingsRequest) returns (ListThingsResponse) {
142-
option (google.api.http) = {get: "/v1/things"};
143+
option (google.api.http) = {get: "/v1/things/{page_size}"};
143144

144145
option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_operation) = {
145146
responses: {
@@ -162,9 +163,21 @@ service ThingService {
162163

163164
// CreateThingRequest is the request for the CreateThing RPC.
164165
message CreateThingRequest {
165-
// The thing to create.
166-
Thing thing = 1;
167-
string a_query_parameter = 2;
166+
// ID is the unique identifier of the thing.
167+
string id = 1 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"123e4567-e89b-12d3-a456-426614174000\""}];
168+
169+
// Name of the thing.
170+
string name = 2 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"A Thing's Name\""}];
171+
172+
// Creation timestamp of the thing.
173+
optional google.protobuf.Timestamp created_at = 4 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"2021-01-01T00:00:00Z\""}];
174+
NestedStruct nested_field = 5;
175+
string preview_field = 6 [(google.api.field_visibility).restriction = "PREVIEW"];
176+
ThingType thing_type = 7 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"THING_TYPE_STANDARD\""}];
177+
oneof polymorphic_field {
178+
PolymorphicVariantA variant_a = 8;
179+
PolymorphicVariantB variant_b = 9;
180+
}
168181
}
169182

170183
// CreateThingResponse is the response for the CreateThing RPC.
@@ -176,16 +189,16 @@ message CreateThingResponse {
176189
// ListThingsRequest is the request for the ListThings RPC.
177190
message ListThingsRequest {
178191
// The filter.
179-
optional string filter = 1; // use whatever type is actually required
192+
string filter = 1; // use whatever type is actually required
180193

181194
// The page size.
182-
optional int32 page_size = 2;
195+
int32 page_size = 2;
183196

184197
// The skip count.
185-
optional int32 skip = 3;
198+
int32 skip = 3;
186199

187200
// The page token.
188-
optional string page_token = 4;
201+
string page_token = 4;
189202
}
190203

191204
// ListThingsResponse is the response for the ListThings RPC.
@@ -203,6 +216,7 @@ message ListThingsResponse {
203216
// ReplaceThingRequest is the request for the ReplaceThing RPC.
204217
message ReplaceThingRequest {
205218
// The thing to replace.
219+
string thing_id = 2;
206220
Thing thing = 1;
207221
}
208222

golden-file-tests/run_golden_file_test.sh

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@
22
cd cx-api && bash build_facade_files.sh
33
cd ..
44

5-
if diff <(jq --sort-keys . apidocs_golden.swagger.json) <(jq --sort-keys . apidocs.swagger.json) > /dev/null; then
6-
echo "Plugin output matches golden file."
5+
if diff <(jq --sort-keys . apidocs_golden.swagger.json | jq 'walk(if type == "object" and has("oneOf") and (.oneOf | type) == "array" then .oneOf |= sort_by(."$ref") else . end)') \
6+
<(jq --sort-keys . apidocs.swagger.json | jq 'walk(if type == "object" and has("oneOf") and (.oneOf | type) == "array" then .oneOf |= sort_by(."$ref") else . end)') > /dev/null; then
7+
echo "Plugin output matches golden file without preview visibility."
78
else
8-
echo "Plugin output does not match golden file."
9+
echo "Plugin output does not match golden file without preview visibility."
10+
exit 1
11+
fi
12+
13+
rm -r apidocs.swagger.json
14+
15+
cd cx-api && bash build_facade_files_with_preview_visibility.sh
16+
cd ..
17+
18+
if diff <(jq --sort-keys . apidocs_golden_preview_visibility.swagger.json | jq 'walk(if type == "object" and has("oneOf") and (.oneOf | type) == "array" then .oneOf |= sort_by(."$ref") else . end)') \
19+
<(jq --sort-keys . apidocs.swagger.json | jq 'walk(if type == "object" and has("oneOf") and (.oneOf | type) == "array" then .oneOf |= sort_by(."$ref") else . end)') > /dev/null; then
20+
echo "Plugin output matches golden file with preview visibility."
21+
else
22+
echo "Plugin output does not match golden file with preview visibility."
923
exit 1
1024
fi
1125

protoc-gen-openapiv3/internal/genopenapi/helpers.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
package genopenapi
55

6+
import (
7+
"strings"
8+
"unicode"
9+
)
10+
611
// this method will filter the same fields and return the unique one
712
func getUniqueFields(schemaFieldsRequired []string, fieldsRequired []string) []string {
813
var unique []string
@@ -23,3 +28,28 @@ func getUniqueFields(schemaFieldsRequired []string, fieldsRequired []string) []s
2328
}
2429
return unique
2530
}
31+
32+
func toPascalCase(s string) string {
33+
if s == "" {
34+
return ""
35+
}
36+
37+
var builder strings.Builder
38+
capitalizeNext := true
39+
40+
for _, r := range s {
41+
if r == '_' {
42+
capitalizeNext = true
43+
continue // Skip the underscore itself
44+
}
45+
46+
if capitalizeNext {
47+
builder.WriteRune(unicode.ToUpper(r))
48+
capitalizeNext = false // Reset the flag
49+
} else {
50+
builder.WriteRune(r)
51+
}
52+
}
53+
54+
return builder.String()
55+
}

0 commit comments

Comments
 (0)