github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/protoc-gen-openapiv2/internal/genopenapi/types.go (about)

     1  package genopenapi
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
     9  	"gopkg.in/yaml.v3"
    10  )
    11  
    12  type param struct {
    13  	*descriptor.File
    14  	reg *descriptor.Registry
    15  }
    16  
    17  // http://swagger.io/specification/#infoObject
    18  type openapiInfoObject struct {
    19  	Title          string `json:"title" yaml:"title"`
    20  	Description    string `json:"description,omitempty" yaml:"description,omitempty"`
    21  	TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
    22  	Version        string `json:"version" yaml:"version"`
    23  
    24  	Contact *openapiContactObject `json:"contact,omitempty" yaml:"contact,omitempty"`
    25  	License *openapiLicenseObject `json:"license,omitempty" yaml:"license,omitempty"`
    26  
    27  	extensions []extension `json:"-" yaml:"-"`
    28  }
    29  
    30  // https://swagger.io/specification/#tagObject
    31  type openapiTagObject struct {
    32  	Name         string                              `json:"name" yaml:"name"`
    33  	Description  string                              `json:"description,omitempty" yaml:"description,omitempty"`
    34  	ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
    35  
    36  	extensions []extension `json:"-" yaml:"-"`
    37  }
    38  
    39  // http://swagger.io/specification/#contactObject
    40  type openapiContactObject struct {
    41  	Name  string `json:"name,omitempty" yaml:"name,omitempty"`
    42  	URL   string `json:"url,omitempty" yaml:"url,omitempty"`
    43  	Email string `json:"email,omitempty" yaml:"email,omitempty"`
    44  }
    45  
    46  // http://swagger.io/specification/#licenseObject
    47  type openapiLicenseObject struct {
    48  	Name string `json:"name,omitempty" yaml:"name,omitempty"`
    49  	URL  string `json:"url,omitempty" yaml:"url,omitempty"`
    50  }
    51  
    52  // http://swagger.io/specification/#externalDocumentationObject
    53  type openapiExternalDocumentationObject struct {
    54  	Description string `json:"description,omitempty" yaml:"description,omitempty"`
    55  	URL         string `json:"url,omitempty" yaml:"url,omitempty"`
    56  }
    57  
    58  type extension struct {
    59  	key   string          `json:"-" yaml:"-"`
    60  	value json.RawMessage `json:"-" yaml:"-"`
    61  }
    62  
    63  // http://swagger.io/specification/#swaggerObject
    64  type openapiSwaggerObject struct {
    65  	Swagger             string                              `json:"swagger" yaml:"swagger"`
    66  	Info                openapiInfoObject                   `json:"info" yaml:"info"`
    67  	Tags                []openapiTagObject                  `json:"tags,omitempty" yaml:"tags,omitempty"`
    68  	Host                string                              `json:"host,omitempty" yaml:"host,omitempty"`
    69  	BasePath            string                              `json:"basePath,omitempty" yaml:"basePath,omitempty"`
    70  	Schemes             []string                            `json:"schemes,omitempty" yaml:"schemes,omitempty"`
    71  	Consumes            []string                            `json:"consumes" yaml:"consumes"`
    72  	Produces            []string                            `json:"produces" yaml:"produces"`
    73  	Paths               openapiPathsObject                  `json:"paths" yaml:"paths"`
    74  	Definitions         openapiDefinitionsObject            `json:"definitions" yaml:"definitions"`
    75  	SecurityDefinitions openapiSecurityDefinitionsObject    `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"`
    76  	Security            []openapiSecurityRequirementObject  `json:"security,omitempty" yaml:"security,omitempty"`
    77  	ExternalDocs        *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
    78  
    79  	extensions []extension `json:"-" yaml:"-"`
    80  }
    81  
    82  // http://swagger.io/specification/#securityDefinitionsObject
    83  type openapiSecurityDefinitionsObject map[string]openapiSecuritySchemeObject
    84  
    85  // http://swagger.io/specification/#securitySchemeObject
    86  type openapiSecuritySchemeObject struct {
    87  	Type             string              `json:"type" yaml:"type"`
    88  	Description      string              `json:"description,omitempty" yaml:"description,omitempty"`
    89  	Name             string              `json:"name,omitempty" yaml:"name,omitempty"`
    90  	In               string              `json:"in,omitempty" yaml:"in,omitempty"`
    91  	Flow             string              `json:"flow,omitempty" yaml:"flow,omitempty"`
    92  	AuthorizationURL string              `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
    93  	TokenURL         string              `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
    94  	Scopes           openapiScopesObject `json:"scopes,omitempty" yaml:"scopes,omitempty"`
    95  
    96  	extensions []extension `json:"-" yaml:"-"`
    97  }
    98  
    99  // http://swagger.io/specification/#scopesObject
   100  type openapiScopesObject map[string]string
   101  
   102  // http://swagger.io/specification/#securityRequirementObject
   103  type openapiSecurityRequirementObject map[string][]string
   104  
   105  // http://swagger.io/specification/#pathsObject
   106  type openapiPathsObject []pathData
   107  
   108  type pathData struct {
   109  	Path           string
   110  	PathItemObject openapiPathItemObject
   111  }
   112  
   113  // http://swagger.io/specification/#pathItemObject
   114  type openapiPathItemObject struct {
   115  	Get     *openapiOperationObject `json:"get,omitempty" yaml:"get,omitempty"`
   116  	Delete  *openapiOperationObject `json:"delete,omitempty" yaml:"delete,omitempty"`
   117  	Post    *openapiOperationObject `json:"post,omitempty" yaml:"post,omitempty"`
   118  	Put     *openapiOperationObject `json:"put,omitempty" yaml:"put,omitempty"`
   119  	Patch   *openapiOperationObject `json:"patch,omitempty" yaml:"patch,omitempty"`
   120  	Head    *openapiOperationObject `json:"head,omitempty" yaml:"head,omitempty"`
   121  	Options *openapiOperationObject `json:"options,omitempty" yaml:"options,omitempty"`
   122  	// While TRACE is supported in OpenAPI v3, it is not supported in OpenAPI v2
   123  	// Trace   *openapiOperationObject `json:"trace,omitempty" yaml:"trace,omitempty"`
   124  }
   125  
   126  // http://swagger.io/specification/#operationObject
   127  type openapiOperationObject struct {
   128  	Summary     string                  `json:"summary,omitempty" yaml:"summary,omitempty"`
   129  	Description string                  `json:"description,omitempty" yaml:"description,omitempty"`
   130  	OperationID string                  `json:"operationId" yaml:"operationId"`
   131  	Responses   openapiResponsesObject  `json:"responses" yaml:"responses"`
   132  	Parameters  openapiParametersObject `json:"parameters,omitempty" yaml:"parameters,omitempty"`
   133  	Tags        []string                `json:"tags,omitempty" yaml:"tags,omitempty"`
   134  	Deprecated  bool                    `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
   135  	Consumes    []string                `json:"consumes,omitempty" yaml:"consumes,omitempty"`
   136  	Produces    []string                `json:"produces,omitempty" yaml:"produces,omitempty"`
   137  
   138  	Security     *[]openapiSecurityRequirementObject `json:"security,omitempty" yaml:"security,omitempty"`
   139  	ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
   140  
   141  	extensions []extension `json:"-" yaml:"-"`
   142  }
   143  
   144  type openapiParametersObject []openapiParameterObject
   145  
   146  // http://swagger.io/specification/#parameterObject
   147  type openapiParameterObject struct {
   148  	Name             string              `json:"name" yaml:"name"`
   149  	Description      string              `json:"description,omitempty" yaml:"description,omitempty"`
   150  	In               string              `json:"in,omitempty" yaml:"in,omitempty"`
   151  	Required         bool                `json:"required" yaml:"required"`
   152  	Type             string              `json:"type,omitempty" yaml:"type,omitempty"`
   153  	Format           string              `json:"format,omitempty" yaml:"format,omitempty"`
   154  	Items            *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"`
   155  	Enum             interface{}         `json:"enum,omitempty" yaml:"enum,omitempty"`
   156  	CollectionFormat string              `json:"collectionFormat,omitempty" yaml:"collectionFormat,omitempty"`
   157  	Default          interface{}         `json:"default,omitempty" yaml:"default,omitempty"`
   158  	MinItems         *int                `json:"minItems,omitempty" yaml:"minItems,omitempty"`
   159  	Pattern          string              `json:"pattern,omitempty" yaml:"pattern,omitempty"`
   160  
   161  	// Or you can explicitly refer to another type. If this is defined all
   162  	// other fields should be empty
   163  	Schema *openapiSchemaObject `json:"schema,omitempty" yaml:"schema,omitempty"`
   164  
   165  	extensions []extension
   166  }
   167  
   168  // core part of schema, which is common to itemsObject and schemaObject.
   169  // http://swagger.io/specification/v2/#itemsObject
   170  // The OAS3 spec (https://swagger.io/specification/#schemaObject) defines the
   171  // `nullable` field as part of a Schema Object. This behavior has been
   172  // "back-ported" to OAS2 as the Specification Extension `x-nullable`, and is
   173  // supported by generation tools such as swagger-codegen and go-swagger.
   174  // For protoc-gen-openapiv3, we'd want to add `nullable` instead.
   175  type schemaCore struct {
   176  	Type      string     `json:"type,omitempty" yaml:"type,omitempty"`
   177  	Format    string     `json:"format,omitempty" yaml:"format,omitempty"`
   178  	Ref       string     `json:"$ref,omitempty" yaml:"$ref,omitempty"`
   179  	XNullable bool       `json:"x-nullable,omitempty" yaml:"x-nullable,omitempty"`
   180  	Example   RawExample `json:"example,omitempty" yaml:"example,omitempty"`
   181  
   182  	Items *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"`
   183  
   184  	// If the item is an enumeration include a list of all the *NAMES* of the
   185  	// enum values.  I'm not sure how well this will work but assuming all enums
   186  	// start from 0 index it will be great. I don't think that is a good assumption.
   187  	Enum    interface{} `json:"enum,omitempty" yaml:"enum,omitempty"`
   188  	Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
   189  }
   190  
   191  type allOfEntry struct {
   192  	Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
   193  }
   194  
   195  type RawExample json.RawMessage
   196  
   197  func (m RawExample) MarshalJSON() ([]byte, error) {
   198  	return (json.RawMessage)(m).MarshalJSON()
   199  }
   200  
   201  func (m *RawExample) UnmarshalJSON(data []byte) error {
   202  	return (*json.RawMessage)(m).UnmarshalJSON(data)
   203  }
   204  
   205  // MarshalYAML implements yaml.Marshaler interface.
   206  //
   207  // It converts RawExample to one of yaml-supported types and returns it.
   208  //
   209  // From yaml.Marshaler docs: The Marshaler interface may be implemented
   210  // by types to customize their behavior when being marshaled into a YAML
   211  // document. The returned value is marshaled in place of the original
   212  // value implementing Marshaler.
   213  func (e RawExample) MarshalYAML() (interface{}, error) {
   214  	// From docs, json.Unmarshal will store one of next types to data:
   215  	// - bool, for JSON booleans;
   216  	// - float64, for JSON numbers;
   217  	// - string, for JSON strings;
   218  	// - []interface{}, for JSON arrays;
   219  	// - map[string]interface{}, for JSON objects;
   220  	// - nil for JSON null.
   221  	var data interface{}
   222  	if err := json.Unmarshal(e, &data); err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	return data, nil
   227  }
   228  
   229  func (s *schemaCore) setRefFromFQN(ref string, reg *descriptor.Registry) error {
   230  	name, ok := fullyQualifiedNameToOpenAPIName(ref, reg)
   231  	if !ok {
   232  		return fmt.Errorf("setRefFromFQN: can't resolve OpenAPI name from %q", ref)
   233  	}
   234  	s.Ref = fmt.Sprintf("#/definitions/%s", name)
   235  	return nil
   236  }
   237  
   238  type openapiItemsObject openapiSchemaObject
   239  
   240  // http://swagger.io/specification/#responsesObject
   241  type openapiResponsesObject map[string]openapiResponseObject
   242  
   243  // http://swagger.io/specification/#responseObject
   244  type openapiResponseObject struct {
   245  	Description string                 `json:"description" yaml:"description"`
   246  	Schema      openapiSchemaObject    `json:"schema" yaml:"schema"`
   247  	Examples    map[string]interface{} `json:"examples,omitempty" yaml:"examples,omitempty"`
   248  	Headers     openapiHeadersObject   `json:"headers,omitempty" yaml:"headers,omitempty"`
   249  
   250  	extensions []extension `json:"-" yaml:"-"`
   251  }
   252  
   253  type openapiHeadersObject map[string]openapiHeaderObject
   254  
   255  // http://swagger.io/specification/#headerObject
   256  type openapiHeaderObject struct {
   257  	Description string     `json:"description,omitempty" yaml:"description,omitempty"`
   258  	Type        string     `json:"type,omitempty" yaml:"type,omitempty"`
   259  	Format      string     `json:"format,omitempty" yaml:"format,omitempty"`
   260  	Default     RawExample `json:"default,omitempty" yaml:"default,omitempty"`
   261  	Pattern     string     `json:"pattern,omitempty" yaml:"pattern,omitempty"`
   262  }
   263  
   264  type keyVal struct {
   265  	Key   string
   266  	Value interface{}
   267  }
   268  
   269  type openapiSchemaObjectProperties []keyVal
   270  
   271  func (p openapiSchemaObjectProperties) MarshalYAML() (interface{}, error) {
   272  	n := yaml.Node{
   273  		Kind:    yaml.MappingNode,
   274  		Content: make([]*yaml.Node, len(p)*2),
   275  	}
   276  	for i, v := range p {
   277  		keyNode := yaml.Node{}
   278  		if err := keyNode.Encode(v.Key); err != nil {
   279  			return nil, err
   280  		}
   281  		valueNode := yaml.Node{}
   282  		if err := valueNode.Encode(v.Value); err != nil {
   283  			return nil, err
   284  		}
   285  		n.Content[i*2+0] = &keyNode
   286  		n.Content[i*2+1] = &valueNode
   287  	}
   288  	return n, nil
   289  }
   290  
   291  func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) {
   292  	var buf bytes.Buffer
   293  	buf.WriteString("{")
   294  	for i, kv := range op {
   295  		if i != 0 {
   296  			buf.WriteString(",")
   297  		}
   298  		key, err := json.Marshal(kv.Key)
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  		buf.Write(key)
   303  		buf.WriteString(":")
   304  		val, err := json.Marshal(kv.Value)
   305  		if err != nil {
   306  			return nil, err
   307  		}
   308  		buf.Write(val)
   309  	}
   310  
   311  	buf.WriteString("}")
   312  	return buf.Bytes(), nil
   313  }
   314  
   315  // http://swagger.io/specification/#schemaObject
   316  type openapiSchemaObject struct {
   317  	schemaCore `yaml:",inline"`
   318  	// Properties can be recursively defined
   319  	Properties           *openapiSchemaObjectProperties `json:"properties,omitempty" yaml:"properties,omitempty"`
   320  	AdditionalProperties *openapiSchemaObject           `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"`
   321  
   322  	Description string `json:"description,omitempty" yaml:"description,omitempty"`
   323  	Title       string `json:"title,omitempty" yaml:"title,omitempty"`
   324  
   325  	ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
   326  
   327  	ReadOnly         bool     `json:"readOnly,omitempty" yaml:"readOnly,omitempty"`
   328  	MultipleOf       float64  `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"`
   329  	Maximum          float64  `json:"maximum,omitempty" yaml:"maximum,omitempty"`
   330  	ExclusiveMaximum bool     `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"`
   331  	Minimum          float64  `json:"minimum,omitempty" yaml:"minimum,omitempty"`
   332  	ExclusiveMinimum bool     `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"`
   333  	MaxLength        uint64   `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
   334  	MinLength        uint64   `json:"minLength,omitempty" yaml:"minLength,omitempty"`
   335  	Pattern          string   `json:"pattern,omitempty" yaml:"pattern,omitempty"`
   336  	MaxItems         uint64   `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
   337  	MinItems         uint64   `json:"minItems,omitempty" yaml:"minItems,omitempty"`
   338  	UniqueItems      bool     `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
   339  	MaxProperties    uint64   `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
   340  	MinProperties    uint64   `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
   341  	Required         []string `json:"required,omitempty" yaml:"required,omitempty"`
   342  
   343  	extensions []extension
   344  
   345  	AllOf []allOfEntry `json:"allOf,omitempty" yaml:"allOf,omitempty"`
   346  }
   347  
   348  // http://swagger.io/specification/#definitionsObject
   349  type openapiDefinitionsObject map[string]openapiSchemaObject
   350  
   351  // Internal type mapping from FQMN to descriptor.Message. Used as a set by the
   352  // findServiceMessages function.
   353  type messageMap map[string]*descriptor.Message
   354  
   355  // Internal type mapping from FQEN to descriptor.Enum. Used as a set by the
   356  // findServiceMessages function.
   357  type enumMap map[string]*descriptor.Enum
   358  
   359  // Internal type to store used references.
   360  type refMap map[string]struct{}