Skip to content

Commit 8359042

Browse files
authored
Document required fields (#198)
Closes: #167
1 parent 2d221d4 commit 8359042

File tree

4 files changed

+1921
-23
lines changed

4 files changed

+1921
-23
lines changed

internal/generate/paths.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func buildMethod(f *os.File, spec *openapi3.T, method string, path string, o *op
141141
}
142142

143143
methodName := strcase.ToCamel(o.OperationID)
144-
pInfo := buildParams(o, method, methodName)
144+
pInfo := buildParams(o, methodName)
145145

146146
// Adapt for ListAll methods
147147
if isGetAllPages && len(pagedRespType) > 0 {
@@ -348,7 +348,7 @@ func buildPathOrQueryParams(paramType string, params map[string]*openapi3.Parame
348348
return pathParams, nil
349349
}
350350

351-
func buildParams(operation *openapi3.Operation, method, opID string) paramsInfo {
351+
func buildParams(operation *openapi3.Operation, opID string) paramsInfo {
352352
pInfo := paramsInfo{
353353
parameters: make(map[string]*openapi3.Parameter, 0),
354354
}

internal/generate/types.go

+49-8
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,32 @@ func constructParamTypes(paths map[string]*openapi3.PathItem) []TypeTemplate {
100100
sort.Strings(keys)
101101
for _, op := range keys {
102102
o := ops[op]
103+
requiredFields := ""
104+
105+
// Some required fields are defined in vendor extensions
106+
for k, v := range o.Extensions {
107+
if k == "x-dropshot-pagination" {
108+
for i, j := range v.(map[string]interface{}) {
109+
if i == "required" {
110+
values, ok := j.([]interface{})
111+
if ok {
112+
for _, field := range values {
113+
str, ok := field.(string)
114+
if ok {
115+
requiredFields = requiredFields + fmt.Sprintf("\n// - %v", strcase.ToCamel(str))
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
}
123+
103124
if len(o.Parameters) > 0 || o.RequestBody != nil {
104125
paramsTypeName := strcase.ToCamel(o.OperationID) + "Params"
105126
paramsTpl := TypeTemplate{
106-
Type: "struct",
107-
Name: paramsTypeName,
108-
Description: "// " + paramsTypeName + " is the request parameters for " + strcase.ToCamel(o.OperationID),
127+
Type: "struct",
128+
Name: paramsTypeName,
109129
}
110130

111131
fields := make([]TypeFields, 0)
@@ -121,6 +141,10 @@ func constructParamTypes(paths map[string]*openapi3.PathItem) []TypeTemplate {
121141
Type: convertToValidGoType("", p.Value.Schema),
122142
}
123143

144+
if p.Value.Required {
145+
requiredFields = requiredFields + fmt.Sprintf("\n// - %s", paramName)
146+
}
147+
124148
serInfo := fmt.Sprintf("`json:\"%s,omitempty\" yaml:\"%s,omitempty\"`", p.Value.Name, p.Value.Name)
125149
field.SerializationInfo = serInfo
126150

@@ -147,9 +171,18 @@ func constructParamTypes(paths map[string]*openapi3.PathItem) []TypeTemplate {
147171
SerializationInfo: "`json:\"body,omitempty\" yaml:\"body,omitempty\"`",
148172
}
149173
}
174+
// Body is always a required field
175+
requiredFields = requiredFields + "\n// - Body"
150176
fields = append(fields, field)
151177
}
152178
paramsTpl.Fields = fields
179+
180+
description := "// " + paramsTypeName + " is the request parameters for " +
181+
strcase.ToCamel(o.OperationID)
182+
if requiredFields != "" {
183+
description = description + "\n//\n// Required fields:" + requiredFields
184+
}
185+
paramsTpl.Description = description
153186
paramTypes = append(paramTypes, paramsTpl)
154187
}
155188
}
@@ -400,7 +433,7 @@ func populateTypeTemplates(name string, s *openapi3.Schema, enumFieldName string
400433
typeTpl.Type = fmt.Sprintf("[]%s", s.Items.Value.Type)
401434
typeTpl.Name = typeName
402435
case "object":
403-
typeTpl = createTypeObject(s.Properties, name, typeName, formatTypeDescription(typeName, s))
436+
typeTpl = createTypeObject(s, name, typeName, formatTypeDescription(typeName, s))
404437

405438
// Iterate over the properties and append the types, if we need to.
406439
for k, v := range s.Properties {
@@ -439,7 +472,7 @@ func populateTypeTemplates(name string, s *openapi3.Schema, enumFieldName string
439472
return types, enumTypes
440473
}
441474

442-
func createTypeObject(schemas map[string]*openapi3.SchemaRef, name, typeName, description string) TypeTemplate {
475+
func createTypeObject(schema *openapi3.Schema, name, typeName, description string) TypeTemplate {
443476
// TODO: Create types out of the schemas instead of plucking them out of the objects
444477
// will leave this for another PR, because the yak shaving is getting ridiculous.
445478
// Tracked -> https://github.com/oxidecomputer/oxide.go/issues/110
@@ -450,11 +483,11 @@ func createTypeObject(schemas map[string]*openapi3.SchemaRef, name, typeName, de
450483
}
451484

452485
typeTpl := TypeTemplate{
453-
Description: description,
454-
Name: typeName,
455-
Type: "struct",
486+
Name: typeName,
487+
Type: "struct",
456488
}
457489

490+
schemas := schema.Properties
458491
// We want to ensure we keep the order
459492
keys := make([]string, 0)
460493
for k := range schemas {
@@ -496,6 +529,14 @@ func createTypeObject(schemas map[string]*openapi3.SchemaRef, name, typeName, de
496529
}
497530
typeTpl.Fields = fields
498531

532+
if len(schema.Required) > 0 {
533+
description = description + "\n//\n// Required fields:"
534+
for _, r := range schema.Required {
535+
description = description + fmt.Sprintf("\n// - %s", strcase.ToCamel(r))
536+
}
537+
}
538+
typeTpl.Description = description
539+
499540
return typeTpl
500541
}
501542

internal/generate/types_test.go

+21-13
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,19 @@ func Test_generateTypes(t *testing.T) {
103103
}
104104

105105
func Test_createTypeObject(t *testing.T) {
106-
typesSpec := map[string]*openapi3.SchemaRef{
107-
"snapshot_id": {
108-
Value: &openapi3.Schema{Type: "string", Format: "uuid"},
109-
},
110-
"type": {
111-
Value: &openapi3.Schema{Type: "string", Enum: []interface{}{"snapshot"}},
112-
},
113-
}
106+
typesSpec := openapi3.Schema{
107+
Required: []string{"type"},
108+
Properties: map[string]*openapi3.SchemaRef{
109+
"snapshot_id": {
110+
Value: &openapi3.Schema{Type: "string", Format: "uuid"},
111+
},
112+
"type": {
113+
Value: &openapi3.Schema{Type: "string", Enum: []interface{}{"snapshot"}},
114+
},
115+
}}
114116

115117
type args struct {
116-
s map[string]*openapi3.SchemaRef
118+
s openapi3.Schema
117119
name string
118120
typeName string
119121
}
@@ -126,7 +128,7 @@ func Test_createTypeObject(t *testing.T) {
126128
name: "success",
127129
args: args{typesSpec, "DiskSource", "DiskSourceSnapshot"},
128130
want: TypeTemplate{
129-
Description: "Create a disk from a disk snapshot",
131+
Description: "Create a disk from a disk snapshot\n//\n// Required fields:\n// - Type",
130132
Name: "DiskSourceSnapshot",
131133
Type: "struct", Fields: []TypeFields{
132134
{
@@ -147,7 +149,7 @@ func Test_createTypeObject(t *testing.T) {
147149
}
148150
for _, tt := range tests {
149151
t.Run(tt.name, func(t *testing.T) {
150-
got := createTypeObject(tt.args.s, tt.args.name, tt.args.typeName, "Create a disk from a disk snapshot")
152+
got := createTypeObject(&tt.args.s, tt.args.name, tt.args.typeName, "Create a disk from a disk snapshot")
151153
assert.Equal(t, tt.want, got)
152154
})
153155
}
@@ -245,7 +247,10 @@ func Test_createOneOf(t *testing.T) {
245247
Description: "// ImageSourceType is the type definition for a ImageSourceType.", Name: "ImageSourceType", Type: "string",
246248
},
247249
{
248-
Description: "// ImageSourceUrl is the type definition for a ImageSourceUrl.", Name: "ImageSourceUrl", Type: "struct", Fields: []TypeFields{
250+
Description: "// ImageSourceUrl is the type definition for a ImageSourceUrl.\n//\n// Required fields:\n// - Type\n// - Url",
251+
Name: "ImageSourceUrl",
252+
Type: "struct",
253+
Fields: []TypeFields{
249254
{
250255
Description: "", Name: "Type", Type: "ImageSourceType", SerializationInfo: "`json:\"type,omitempty\" yaml:\"type,omitempty\"`",
251256
},
@@ -255,7 +260,10 @@ func Test_createOneOf(t *testing.T) {
255260
},
256261
},
257262
{
258-
Description: "// ImageSourceSnapshot is the type definition for a ImageSourceSnapshot.", Name: "ImageSourceSnapshot", Type: "struct", Fields: []TypeFields{
263+
Description: "// ImageSourceSnapshot is the type definition for a ImageSourceSnapshot.\n//\n// Required fields:\n// - Id\n// - Type",
264+
Name: "ImageSourceSnapshot",
265+
Type: "struct",
266+
Fields: []TypeFields{
259267
{
260268
Description: "", Name: "Id", Type: "string", SerializationInfo: "`json:\"id,omitempty\" yaml:\"id,omitempty\"`",
261269
},

0 commit comments

Comments
 (0)