package openapi // import "udico.de/uditaren/opier/openapi" import ( "fmt" "gopkg.in/yaml.v3" "os" "strings" "unicode" ) type OpenAPI struct { Version string `yaml:"openapi"` Info struct { Title string Version string Description string } Paths map[string]*PathItem `yaml:"paths"` Components *Components } func Load(fname string) (*OpenAPI, error) { f, err := os.Open(fname) if err != nil { return nil, err } tRet := &OpenAPI{} tY := yaml.NewDecoder(f) err = tY.Decode(tRet) return tRet, err } // PathItem Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. // The path itself is still exposed to the documentation viewer but they will not know which operations and parameters // are available. type PathItem struct { // Allows for an external definition of this path item. The referenced structure MUST be in the format of a // PathItem Object. In case a PathItem Object field appears both in the defined object and the referenced object, // the behavior is undefined. Ref string `yaml:"$ref"` // An optional, string summary, intended to apply to all operations in this path. Summary string // An optional, string description, intended to apply to all operations in this path. CommonMark syntax MAY be // used for rich text representation. Description string Get *Operation Put *Operation Post *Operation Delete *Operation Options *Operation Head *Operation Patch *Operation Trace *Operation } func (p PathItem) Operations() map[string]*Operation { tRet := make(map[string]*Operation) if p.Get != nil { tRet["get"] = p.Get } if p.Put != nil { tRet["put"] = p.Put } if p.Post != nil { tRet["post"] = p.Post } if p.Delete != nil { tRet["delete"] = p.Delete } if p.Options != nil { tRet["options"] = p.Options } if p.Head != nil { tRet["head"] = p.Head } if p.Patch != nil { tRet["patch"] = p.Patch } if p.Trace != nil { tRet["trace"] = p.Trace } return tRet } // Operation describes a single API operation on a path. type Operation struct { // A list of tags for API documentation control. Tags can be used for logical grouping of operations // by resources or any other qualifier. Tags []string // A short summary of what the operation does. Summary string // A verbose explanation of the operation behavior. CommonMark syntax MAY be used for rich text representation. Description string // Additional external documentation for this operation. //externalDocs // Unique string used to identify the operation. The id MUST be unique among all operations described in the API. // The operationId value is case-sensitive. Tools and libraries MAY use the operationId to uniquely identify an // operation, therefore, it is RECOMMENDED to follow common programming naming conventions. OperationId string `yaml:"operationId"` //Parameters [] ... // requestBodyesObject // required // callba // Responses Responscks Deprecated bool // A declaration of which security mechanisms can be used for this operation. // The list of values includes alternative security requirement objects that can be used. Only one of the security // requirement objects need to be satisfied to authorize a request. To make security optional, an empty security // requirement ({}) can be included in the array. This definition overrides any declared top-level security. // To remove a top-level security declaration, an empty array can be used. Security []map[string][]string `yaml:"security"` // An alternative server array to service this operation. If an alternative server object is specified at the Path // Item Object or Root level, it will be overridden by this value. // Servers } type ResponsesObject struct { // ... } type Components struct { //SecuritySchemas //Responses map[string, ResponseObject] Parameters map[string]Parameter Schemas map[string]Schema } type ParameterLocation string const ( QUERY ParameterLocation = "query" HEAD = "header" PATH = "path" COOKIE = "cookie" ) type Parameter struct { // only if this a reference object instead of a parameter obect Ref string `yaml:"$ref"` Name string In ParameterLocation Description string Required bool Deprecated bool AllowEmptyValue bool `yaml:"allowEmptyValue"` ///--- either Style string Explode bool AllowReserved bool `yaml:"allowReserved"` Schema *Schema // example // examples ///--- or Content map[string]*MediaType } type Schema struct { // may be a schema reference: Ref string `yaml:"$ref"` Type string // when type==array: Items *Schema // when type==object Properties map[string]*Schema Format string Minimum int Maximum int Default interface{} Enum []interface{} XEnumVarnames []string `yaml:"x-enum-varnames"` Required []string Description string } func (s Schema) TypeOrReference() string { if s.Ref != "" { return s.Ref } return s.Type } func (s Schema) GoType() string { tRet := s.Type if s.Ref != "" { idx := strings.LastIndex(s.Ref, "/") tRet = "*" + s.Ref[idx+1:] } else { switch s.Type { case "integer": tRet = "int" case "boolean": tRet = "bool" case "array": tRet = fmt.Sprintf("[]%v", s.Items.GoType()) } } return tRet } // EnumNames returns the String representations for this enums values and the length of the longest name as well. func (s Schema) EnumNames() ([]string, int) { tLen := 0 tRet := make([]string, len(s.Enum), len(s.Enum)) for k, v := range s.Enum { tName := NormalizeName(fmt.Sprintf("%v", v)) if len(s.XEnumVarnames) == len(s.Enum) { // read the desired enum name instead tName = s.XEnumVarnames[k] } tRet[k] = tName if len(tName) > tLen { tLen = len(tName) } } return tRet, tLen } type Referencable interface { } type MediaType struct { } func NormalizeName(aName string) string { tRet := &strings.Builder{} capitalizeNext := true for _, rune := range aName { if capitalizeNext { tRet.WriteRune(unicode.ToUpper(rune)) capitalizeNext = false } else { if rune == '-' { capitalizeNext = true } else { tRet.WriteRune(rune) } } } return tRet.String() }