k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/util/proto/openapi.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package proto 18 19 import ( 20 "fmt" 21 "sort" 22 "strings" 23 ) 24 25 // Defines openapi types. 26 const ( 27 Integer = "integer" 28 Number = "number" 29 String = "string" 30 Boolean = "boolean" 31 32 // These types are private as they should never leak, and are 33 // represented by actual structs. 34 array = "array" 35 object = "object" 36 ) 37 38 // Models interface describe a model provider. They can give you the 39 // schema for a specific model. 40 type Models interface { 41 LookupModel(string) Schema 42 ListModels() []string 43 } 44 45 // SchemaVisitor is an interface that you need to implement if you want 46 // to "visit" an openapi schema. A dispatch on the Schema type will call 47 // the appropriate function based on its actual type: 48 // - Array is a list of one and only one given subtype 49 // - Map is a map of string to one and only one given subtype 50 // - Primitive can be string, integer, number and boolean. 51 // - Kind is an object with specific fields mapping to specific types. 52 // - Reference is a link to another definition. 53 type SchemaVisitor interface { 54 VisitArray(*Array) 55 VisitMap(*Map) 56 VisitPrimitive(*Primitive) 57 VisitKind(*Kind) 58 VisitReference(Reference) 59 } 60 61 // SchemaVisitorArbitrary is an additional visitor interface which handles 62 // arbitrary types. For backwards compatibility, it's a separate interface 63 // which is checked for at runtime. 64 type SchemaVisitorArbitrary interface { 65 SchemaVisitor 66 VisitArbitrary(*Arbitrary) 67 } 68 69 // Schema is the base definition of an openapi type. 70 type Schema interface { 71 // Giving a visitor here will let you visit the actual type. 72 Accept(SchemaVisitor) 73 74 // Pretty print the name of the type. 75 GetName() string 76 // Describes how to access this field. 77 GetPath() *Path 78 // Describes the field. 79 GetDescription() string 80 // Default for that schema. 81 GetDefault() interface{} 82 // Returns type extensions. 83 GetExtensions() map[string]interface{} 84 } 85 86 // Path helps us keep track of type paths 87 type Path struct { 88 parent *Path 89 key string 90 } 91 92 func NewPath(key string) Path { 93 return Path{key: key} 94 } 95 96 func (p *Path) Get() []string { 97 if p == nil { 98 return []string{} 99 } 100 if p.key == "" { 101 return p.parent.Get() 102 } 103 return append(p.parent.Get(), p.key) 104 } 105 106 func (p *Path) Len() int { 107 return len(p.Get()) 108 } 109 110 func (p *Path) String() string { 111 return strings.Join(p.Get(), "") 112 } 113 114 // ArrayPath appends an array index and creates a new path 115 func (p *Path) ArrayPath(i int) Path { 116 return Path{ 117 parent: p, 118 key: fmt.Sprintf("[%d]", i), 119 } 120 } 121 122 // FieldPath appends a field name and creates a new path 123 func (p *Path) FieldPath(field string) Path { 124 return Path{ 125 parent: p, 126 key: fmt.Sprintf(".%s", field), 127 } 128 } 129 130 // BaseSchema holds data used by each types of schema. 131 type BaseSchema struct { 132 Description string 133 Extensions map[string]interface{} 134 Default interface{} 135 136 Path Path 137 } 138 139 func (b *BaseSchema) GetDescription() string { 140 return b.Description 141 } 142 143 func (b *BaseSchema) GetExtensions() map[string]interface{} { 144 return b.Extensions 145 } 146 147 func (b *BaseSchema) GetDefault() interface{} { 148 return b.Default 149 } 150 151 func (b *BaseSchema) GetPath() *Path { 152 return &b.Path 153 } 154 155 // Array must have all its element of the same `SubType`. 156 type Array struct { 157 BaseSchema 158 159 SubType Schema 160 } 161 162 var _ Schema = &Array{} 163 164 func (a *Array) Accept(v SchemaVisitor) { 165 v.VisitArray(a) 166 } 167 168 func (a *Array) GetName() string { 169 return fmt.Sprintf("Array of %s", a.SubType.GetName()) 170 } 171 172 // Kind is a complex object. It can have multiple different 173 // subtypes for each field, as defined in the `Fields` field. Mandatory 174 // fields are listed in `RequiredFields`. The key of the object is 175 // always of type `string`. 176 type Kind struct { 177 BaseSchema 178 179 // Lists names of required fields. 180 RequiredFields []string 181 // Maps field names to types. 182 Fields map[string]Schema 183 // FieldOrder reports the canonical order for the fields. 184 FieldOrder []string 185 } 186 187 var _ Schema = &Kind{} 188 189 func (k *Kind) Accept(v SchemaVisitor) { 190 v.VisitKind(k) 191 } 192 193 func (k *Kind) GetName() string { 194 properties := []string{} 195 for key := range k.Fields { 196 properties = append(properties, key) 197 } 198 return fmt.Sprintf("Kind(%v)", properties) 199 } 200 201 // IsRequired returns true if `field` is a required field for this type. 202 func (k *Kind) IsRequired(field string) bool { 203 for _, f := range k.RequiredFields { 204 if f == field { 205 return true 206 } 207 } 208 return false 209 } 210 211 // Keys returns a alphabetically sorted list of keys. 212 func (k *Kind) Keys() []string { 213 keys := make([]string, 0) 214 for key := range k.Fields { 215 keys = append(keys, key) 216 } 217 sort.Strings(keys) 218 return keys 219 } 220 221 // Map is an object who values must all be of the same `SubType`. 222 // The key of the object is always of type `string`. 223 type Map struct { 224 BaseSchema 225 226 SubType Schema 227 } 228 229 var _ Schema = &Map{} 230 231 func (m *Map) Accept(v SchemaVisitor) { 232 v.VisitMap(m) 233 } 234 235 func (m *Map) GetName() string { 236 return fmt.Sprintf("Map of %s", m.SubType.GetName()) 237 } 238 239 // Primitive is a literal. There can be multiple types of primitives, 240 // and this subtype can be visited through the `subType` field. 241 type Primitive struct { 242 BaseSchema 243 244 // Type of a primitive must be one of: integer, number, string, boolean. 245 Type string 246 Format string 247 } 248 249 var _ Schema = &Primitive{} 250 251 func (p *Primitive) Accept(v SchemaVisitor) { 252 v.VisitPrimitive(p) 253 } 254 255 func (p *Primitive) GetName() string { 256 if p.Format == "" { 257 return p.Type 258 } 259 return fmt.Sprintf("%s (%s)", p.Type, p.Format) 260 } 261 262 // Arbitrary is a value of any type (primitive, object or array) 263 type Arbitrary struct { 264 BaseSchema 265 } 266 267 var _ Schema = &Arbitrary{} 268 269 func (a *Arbitrary) Accept(v SchemaVisitor) { 270 if visitor, ok := v.(SchemaVisitorArbitrary); ok { 271 visitor.VisitArbitrary(a) 272 } 273 } 274 275 func (a *Arbitrary) GetName() string { 276 return "Arbitrary value (primitive, object or array)" 277 } 278 279 // Reference implementation depends on the type of document. 280 type Reference interface { 281 Schema 282 283 Reference() string 284 SubSchema() Schema 285 }