1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package common 18 19import ( 20 "net/http" 21 "strings" 22 23 "github.com/emicklei/go-restful" 24 "github.com/go-openapi/spec" 25) 26 27const ( 28 // TODO: Make this configurable. 29 ExtensionPrefix = "x-kubernetes-" 30 ExtensionV2Schema = ExtensionPrefix + "v2-schema" 31) 32 33// OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi. 34type OpenAPIDefinition struct { 35 Schema spec.Schema 36 Dependencies []string 37} 38 39type ReferenceCallback func(path string) spec.Ref 40 41// GetOpenAPIDefinitions is collection of all definitions. 42type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition 43 44// OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface, 45// the definition returned by it will be used, otherwise the auto-generated definitions will be used. See 46// GetOpenAPITypeFormat for more information about trade-offs of using this interface or GetOpenAPITypeFormat method when 47// possible. 48type OpenAPIDefinitionGetter interface { 49 OpenAPIDefinition() *OpenAPIDefinition 50} 51 52type OpenAPIV3DefinitionGetter interface { 53 OpenAPIV3Definition() *OpenAPIDefinition 54} 55 56type PathHandler interface { 57 Handle(path string, handler http.Handler) 58} 59 60// Config is set of configuration for openAPI spec generation. 61type Config struct { 62 // List of supported protocols such as https, http, etc. 63 ProtocolList []string 64 65 // Info is general information about the API. 66 Info *spec.Info 67 68 // DefaultResponse will be used if an operation does not have any responses listed. It 69 // will show up as ... "responses" : {"default" : $DefaultResponse} in the spec. 70 DefaultResponse *spec.Response 71 72 // ResponseDefinitions will be added to "responses" under the top-level swagger object. This is an object 73 // that holds responses definitions that can be used across operations. This property does not define 74 // global responses for all operations. For more info please refer: 75 // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields 76 ResponseDefinitions map[string]spec.Response 77 78 // CommonResponses will be added as a response to all operation specs. This is a good place to add common 79 // responses such as authorization failed. 80 CommonResponses map[int]spec.Response 81 82 // List of webservice's path prefixes to ignore 83 IgnorePrefixes []string 84 85 // OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map 86 // or any of the models will result in spec generation failure. 87 GetDefinitions GetOpenAPIDefinitions 88 89 // GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs. 90 GetOperationIDAndTags func(r *restful.Route) (string, []string, error) 91 92 // GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition. 93 // It is an optional function to customize model names. 94 GetDefinitionName func(name string) (string, spec.Extensions) 95 96 // PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving. 97 PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error) 98 99 // SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config 100 // is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses. 101 SecurityDefinitions *spec.SecurityDefinitions 102 103 // DefaultSecurity for all operations. This will pass as spec.SwaggerProps.Security to OpenAPI. 104 // For most cases, this will be list of acceptable definitions in SecurityDefinitions. 105 DefaultSecurity []map[string][]string 106} 107 108var schemaTypeFormatMap = map[string][]string{ 109 "uint": {"integer", "int32"}, 110 "uint8": {"integer", "byte"}, 111 "uint16": {"integer", "int32"}, 112 "uint32": {"integer", "int64"}, 113 "uint64": {"integer", "int64"}, 114 "int": {"integer", "int32"}, 115 "int8": {"integer", "byte"}, 116 "int16": {"integer", "int32"}, 117 "int32": {"integer", "int32"}, 118 "int64": {"integer", "int64"}, 119 "byte": {"integer", "byte"}, 120 "float64": {"number", "double"}, 121 "float32": {"number", "float"}, 122 "bool": {"boolean", ""}, 123 "time.Time": {"string", "date-time"}, 124 "string": {"string", ""}, 125 "integer": {"integer", ""}, 126 "number": {"number", ""}, 127 "boolean": {"boolean", ""}, 128 "[]byte": {"string", "byte"}, // base64 encoded characters 129 "interface{}": {"object", ""}, 130} 131 132// This function is a reference for converting go (or any custom type) to a simple open API type,format pair. There are 133// two ways to customize spec for a type. If you add it here, a type will be converted to a simple type and the type 134// comment (the comment that is added before type definition) will be lost. The spec will still have the property 135// comment. The second way is to implement OpenAPIDefinitionGetter interface. That function can customize the spec (so 136// the spec does not need to be simple type,format) or can even return a simple type,format (e.g. IntOrString). For simple 137// type formats, the benefit of adding OpenAPIDefinitionGetter interface is to keep both type and property documentation. 138// Example: 139// type Sample struct { 140// ... 141// // port of the server 142// port IntOrString 143// ... 144// } 145// // IntOrString documentation... 146// type IntOrString { ... } 147// 148// Adding IntOrString to this function: 149// "port" : { 150// format: "string", 151// type: "int-or-string", 152// Description: "port of the server" 153// } 154// 155// Implement OpenAPIDefinitionGetter for IntOrString: 156// 157// "port" : { 158// $Ref: "#/definitions/IntOrString" 159// Description: "port of the server" 160// } 161// ... 162// definitions: 163// { 164// "IntOrString": { 165// format: "string", 166// type: "int-or-string", 167// Description: "IntOrString documentation..." // new 168// } 169// } 170// 171func GetOpenAPITypeFormat(typeName string) (string, string) { 172 mapped, ok := schemaTypeFormatMap[typeName] 173 if !ok { 174 return "", "" 175 } 176 return mapped[0], mapped[1] 177} 178 179func EscapeJsonPointer(p string) string { 180 // Escaping reference name using rfc6901 181 p = strings.Replace(p, "~", "~0", -1) 182 p = strings.Replace(p, "/", "~1", -1) 183 return p 184} 185 186func EmbedOpenAPIDefinitionIntoV2Extension(main OpenAPIDefinition, embedded OpenAPIDefinition) OpenAPIDefinition { 187 if main.Schema.Extensions == nil { 188 main.Schema.Extensions = make(map[string]interface{}) 189 } 190 main.Schema.Extensions[ExtensionV2Schema] = embedded.Schema 191 return main 192} 193