Skip to content

Commit e0d9f07

Browse files
committed
Add OpenAPIConv
1 parent 29d7264 commit e0d9f07

File tree

16 files changed

+656
-21
lines changed

16 files changed

+656
-21
lines changed

pkg/builder3/openapi.go

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const (
3636
)
3737

3838
type openAPI struct {
39-
config *common.Config
39+
config *common.OpenAPIV3Config
4040
spec *spec3.OpenAPI
4141
definitions map[string]common.OpenAPIDefinition
4242
}
@@ -83,6 +83,15 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
8383
},
8484
},
8585
}
86+
for k, v := range route.Metadata() {
87+
if strings.HasPrefix(k, common.ExtensionPrefix) {
88+
if ret.Extensions == nil {
89+
ret.Extensions = spec.Extensions{}
90+
}
91+
ret.Extensions.Add(k, v)
92+
}
93+
}
94+
8695
var err error
8796
if ret.OperationId, ret.Tags, err = o.config.GetOperationIDAndTagsFromRoute(route); err != nil {
8897
return ret, err
@@ -104,9 +113,16 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
104113
}
105114
}
106115

107-
// TODO: Default response if needed. Common Response config
116+
for code, resp := range o.config.CommonResponses {
117+
if _, exists := ret.Responses.StatusCodeResponses[code]; !exists {
118+
ret.Responses.StatusCodeResponses[code] = resp
119+
}
120+
}
121+
122+
if o.config.DefaultResponse != nil {
123+
ret.Responses.Default = o.config.DefaultResponse
124+
}
108125

109-
ret.Parameters = make([]*spec3.Parameter, 0)
110126
params := route.Parameters()
111127
for _, param := range params {
112128
_, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]
@@ -119,7 +135,7 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
119135
}
120136
}
121137

122-
body, err := o.buildRequestBody(params, route.RequestPayloadSample())
138+
body, err := o.buildRequestBody(params, route.Consumes(), route.RequestPayloadSample())
123139
if err != nil {
124140
return nil, err
125141
}
@@ -130,7 +146,7 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
130146
return ret, nil
131147
}
132148

133-
func (o *openAPI) buildRequestBody(parameters []common.Parameter, bodySample interface{}) (*spec3.RequestBody, error) {
149+
func (o *openAPI) buildRequestBody(parameters []common.Parameter, consumes []string, bodySample interface{}) (*spec3.RequestBody, error) {
134150
for _, param := range parameters {
135151
if param.Kind() == common.BodyParameterKind && bodySample != nil {
136152
schema, err := o.toSchema(util.GetCanonicalTypeName(bodySample))
@@ -139,15 +155,16 @@ func (o *openAPI) buildRequestBody(parameters []common.Parameter, bodySample int
139155
}
140156
r := &spec3.RequestBody{
141157
RequestBodyProps: spec3.RequestBodyProps{
142-
Content: map[string]*spec3.MediaType{
143-
"application/json": &spec3.MediaType{
144-
MediaTypeProps: spec3.MediaTypeProps{
145-
Schema: schema,
146-
},
147-
},
148-
},
158+
Content: map[string]*spec3.MediaType{},
149159
},
150160
}
161+
for _, consume := range consumes {
162+
r.Content[consume] = &spec3.MediaType{
163+
MediaTypeProps: spec3.MediaTypeProps{
164+
Schema: schema,
165+
},
166+
}
167+
}
151168
return r, nil
152169
}
153170
}
@@ -156,7 +173,7 @@ func (o *openAPI) buildRequestBody(parameters []common.Parameter, bodySample int
156173

157174
func newOpenAPI(config *common.Config) openAPI {
158175
o := openAPI{
159-
config: config,
176+
config: common.ConvertConfigToV3(config),
160177
spec: &spec3.OpenAPI{
161178
Version: "3.0.0",
162179
Info: config.Info,
@@ -168,6 +185,21 @@ func newOpenAPI(config *common.Config) openAPI {
168185
},
169186
},
170187
}
188+
if len(o.config.ResponseDefinitions) > 0 {
189+
o.spec.Components.Responses = make(map[string]*spec3.Response)
190+
191+
}
192+
for k, response := range o.config.ResponseDefinitions {
193+
o.spec.Components.Responses[k] = response
194+
}
195+
196+
if len(o.config.SecuritySchemes) > 0 {
197+
o.spec.Components.SecuritySchemes = make(spec3.SecuritySchemes)
198+
199+
}
200+
for k, securityScheme := range o.config.SecuritySchemes {
201+
o.spec.Components.SecuritySchemes[k] = securityScheme
202+
}
171203

172204
if o.config.GetOperationIDAndTagsFromRoute == nil {
173205
// Map the deprecated handler to the common interface, if provided.
@@ -235,9 +267,7 @@ func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error {
235267
}
236268

237269
pathItem = &spec3.Path{
238-
PathProps: spec3.PathProps{
239-
Parameters: make([]*spec3.Parameter, 0),
240-
},
270+
PathProps: spec3.PathProps{},
241271
}
242272

243273
// add web services's parameters as well as any parameters appears in all ops, as common parameters
@@ -249,6 +279,7 @@ func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error {
249279

250280
for _, route := range routes {
251281
op, _ := o.buildOperations(route, inPathCommonParamsMap)
282+
sortParameters(op.Parameters)
252283

253284
switch strings.ToUpper(route.Method()) {
254285
case "GET":

pkg/common/common.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222

2323
"github.com/emicklei/go-restful"
2424

25+
"k8s.io/kube-openapi/pkg/openapiconv"
26+
"k8s.io/kube-openapi/pkg/spec3"
2527
"k8s.io/kube-openapi/pkg/validation/spec"
2628
)
2729

@@ -117,6 +119,86 @@ type Config struct {
117119
DefaultSecurity []map[string][]string
118120
}
119121

122+
// OpenAPIV3Config is set of configuration for OpenAPI V3 spec generation.
123+
type OpenAPIV3Config struct {
124+
// Info is general information about the API.
125+
Info *spec.Info
126+
127+
// DefaultResponse will be used if an operation does not have any responses listed. It
128+
// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec.
129+
DefaultResponse *spec3.Response
130+
131+
// ResponseDefinitions will be added to responses component. This is an object
132+
// that holds responses that can be used across operations.
133+
ResponseDefinitions map[string]*spec3.Response
134+
135+
// CommonResponses will be added as a response to all operation specs. This is a good place to add common
136+
// responses such as authorization failed.
137+
CommonResponses map[int]*spec3.Response
138+
139+
// List of webservice's path prefixes to ignore
140+
IgnorePrefixes []string
141+
142+
// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
143+
// or any of the models will result in spec generation failure.
144+
GetDefinitions GetOpenAPIDefinitions
145+
146+
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
147+
//
148+
// Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route
149+
// interface set of funcs.
150+
GetOperationIDAndTags func(r *restful.Route) (string, []string, error)
151+
152+
// GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs.
153+
GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error)
154+
155+
// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
156+
// It is an optional function to customize model names.
157+
GetDefinitionName func(name string) (string, spec.Extensions)
158+
159+
// SecuritySchemes is list of all security schemes for OpenAPI service.
160+
SecuritySchemes spec3.SecuritySchemes
161+
162+
// DefaultSecurity for all operations.
163+
DefaultSecurity []map[string][]string
164+
}
165+
166+
// ConvertConfigToV3 converts a Config object to an OpenAPIV3Config object
167+
func ConvertConfigToV3(config *Config) *OpenAPIV3Config {
168+
if config == nil {
169+
return nil
170+
}
171+
172+
v3Config := &OpenAPIV3Config{
173+
Info: config.Info,
174+
IgnorePrefixes: config.IgnorePrefixes,
175+
GetDefinitions: config.GetDefinitions,
176+
GetOperationIDAndTags: config.GetOperationIDAndTags,
177+
GetOperationIDAndTagsFromRoute: config.GetOperationIDAndTagsFromRoute,
178+
GetDefinitionName: config.GetDefinitionName,
179+
SecuritySchemes: make(spec3.SecuritySchemes),
180+
DefaultSecurity: config.DefaultSecurity,
181+
DefaultResponse: openapiconv.ConvertResponse(config.DefaultResponse, []string{"application/json"}),
182+
183+
CommonResponses: make(map[int]*spec3.Response),
184+
ResponseDefinitions: make(map[string]*spec3.Response),
185+
}
186+
187+
if config.SecurityDefinitions != nil {
188+
for s, securityScheme := range *config.SecurityDefinitions {
189+
v3Config.SecuritySchemes[s] = openapiconv.ConvertSecurityScheme(securityScheme)
190+
}
191+
}
192+
for k, commonResponse := range config.CommonResponses {
193+
v3Config.CommonResponses[k] = openapiconv.ConvertResponse(&commonResponse, []string{"application/json"})
194+
}
195+
196+
for k, responseDefinition := range config.ResponseDefinitions {
197+
v3Config.ResponseDefinitions[k] = openapiconv.ConvertResponse(&responseDefinition, []string{"application/json"})
198+
}
199+
return v3Config
200+
}
201+
120202
type typeInfo struct {
121203
name string
122204
format string

0 commit comments

Comments
 (0)