parser.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package convert
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "os"
  8. "strings"
  9. "github.com/getkin/kin-openapi/openapi2"
  10. "github.com/getkin/kin-openapi/openapi2conv"
  11. "github.com/getkin/kin-openapi/openapi3"
  12. )
  13. // Parser represents an OpenAPI parser
  14. type Parser struct {
  15. doc *openapi3.T
  16. }
  17. // NewParser creates a new OpenAPI parser
  18. func NewParser() *Parser {
  19. return &Parser{}
  20. }
  21. func getFronHTTP(u string) ([]byte, error) {
  22. req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, u, nil)
  23. if err != nil {
  24. return nil, err
  25. }
  26. resp, err := http.DefaultClient.Do(req)
  27. if err != nil {
  28. return nil, err
  29. }
  30. defer resp.Body.Close()
  31. return io.ReadAll(resp.Body)
  32. }
  33. // ParseFile parses an OpenAPI document from a file
  34. func (p *Parser) ParseFile(filePath string) error {
  35. if strings.HasPrefix(filePath, "http://") || strings.HasPrefix(filePath, "https://") {
  36. data, err := getFronHTTP(filePath)
  37. if err != nil {
  38. return err
  39. }
  40. return p.Parse(data)
  41. }
  42. data, err := os.ReadFile(filePath)
  43. if err != nil {
  44. return fmt.Errorf("failed to read OpenAPI file: %w", err)
  45. }
  46. return p.Parse(data)
  47. }
  48. func (p *Parser) ParseFileV2(filePath string) error {
  49. if strings.HasPrefix(filePath, "http://") || strings.HasPrefix(filePath, "https://") {
  50. data, err := getFronHTTP(filePath)
  51. if err != nil {
  52. return err
  53. }
  54. return p.Parse(data)
  55. }
  56. data, err := os.ReadFile(filePath)
  57. if err != nil {
  58. return fmt.Errorf("failed to read OpenAPI file: %w", err)
  59. }
  60. return p.ParseV2(data)
  61. }
  62. // Parse parses an OpenAPI document from bytes
  63. func (p *Parser) Parse(data []byte) error {
  64. loader := openapi3.NewLoader()
  65. // Parse the document (loader can handle both JSON and YAML)
  66. doc, err := loader.LoadFromData(data)
  67. if err != nil {
  68. return fmt.Errorf("failed to parse OpenAPI document: %w", err)
  69. }
  70. p.doc = doc
  71. return nil
  72. }
  73. func (p *Parser) ParseV2(data []byte) error {
  74. var doc2 openapi2.T
  75. err := doc2.UnmarshalJSON(data)
  76. if err != nil {
  77. return fmt.Errorf("failed to parse OpenAPI document: %w", err)
  78. }
  79. doc3, err := openapi2conv.ToV3(&doc2)
  80. if err != nil {
  81. return fmt.Errorf("failed to convert OpenAPI document: %w", err)
  82. }
  83. p.doc = doc3
  84. return nil
  85. }
  86. // GetDocument returns the parsed OpenAPI document
  87. func (p *Parser) GetDocument() *openapi3.T {
  88. return p.doc
  89. }
  90. // GetPaths returns all paths in the OpenAPI document
  91. func (p *Parser) GetPaths() *openapi3.Paths {
  92. if p.doc == nil {
  93. return nil
  94. }
  95. return p.doc.Paths
  96. }
  97. // GetServers returns all servers in the OpenAPI document
  98. func (p *Parser) GetServers() []*openapi3.Server {
  99. if p.doc == nil {
  100. return nil
  101. }
  102. return p.doc.Servers
  103. }
  104. // GetInfo returns the info section of the OpenAPI document
  105. func (p *Parser) GetInfo() *openapi3.Info {
  106. if p.doc == nil {
  107. return nil
  108. }
  109. return p.doc.Info
  110. }
  111. // GetOperationID generates an operation ID if one is not provided
  112. func (p *Parser) GetOperationID(path, method string, operation *openapi3.Operation) string {
  113. if operation.OperationID != "" {
  114. return operation.OperationID
  115. }
  116. // Generate an operation ID based on the path and method
  117. pathParts := strings.Split(strings.Trim(path, "/"), "/")
  118. var pathName string
  119. if len(pathParts) > 0 {
  120. pathName = strings.Join(pathParts, "_")
  121. pathName = strings.ReplaceAll(pathName, "{", "")
  122. pathName = strings.ReplaceAll(pathName, "}", "")
  123. } else {
  124. pathName = "root"
  125. }
  126. return fmt.Sprintf("%s_%s", strings.ToLower(method), pathName)
  127. }