github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/apidef/importer/swagger.go (about)

     1  package importer
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"io"
     7  	"strings"
     8  
     9  	uuid "github.com/satori/go.uuid"
    10  
    11  	"github.com/TykTechnologies/tyk/apidef"
    12  )
    13  
    14  const SwaggerSource APIImporterSource = "swagger"
    15  
    16  type DefinitionObjectFormatAST struct {
    17  	Format string `json:"format"`
    18  	Type   string `json:"type"`
    19  }
    20  
    21  type DefinitionObjectAST struct {
    22  	Type       string                               `json:"type"`
    23  	Required   []string                             `json:"required"`
    24  	Properties map[string]DefinitionObjectFormatAST `json:"properties"`
    25  }
    26  
    27  type ResponseCodeObjectAST struct {
    28  	Description string `json:"description"`
    29  	Schema      struct {
    30  		Items map[string]interface{} `json:"items"`
    31  		Type  string                 `json:"type"`
    32  	} `json:"schema"`
    33  }
    34  
    35  type PathMethodObject struct {
    36  	Description string                           `json:"description"`
    37  	OperationID string                           `json:"operationId"`
    38  	Responses   map[string]ResponseCodeObjectAST `json:"responses"`
    39  }
    40  
    41  type PathItemObject struct {
    42  	Get     PathMethodObject `json:"get"`
    43  	Put     PathMethodObject `json:"put"`
    44  	Post    PathMethodObject `json:"post"`
    45  	Patch   PathMethodObject `json:"patch"`
    46  	Options PathMethodObject `json:"options"`
    47  	Delete  PathMethodObject `json:"delete"`
    48  	Head    PathMethodObject `json:"head"`
    49  }
    50  
    51  type SwaggerAST struct {
    52  	BasePath    string                         `json:"basePath"`
    53  	Consumes    []string                       `json:"consumes"`
    54  	Definitions map[string]DefinitionObjectAST `json:"definitions"`
    55  	Host        string                         `json:"host"`
    56  	Info        struct {
    57  		Contact struct {
    58  			Email string `json:"email"`
    59  			Name  string `json:"name"`
    60  			URL   string `json:"url"`
    61  		} `json:"contact"`
    62  		Description string `json:"description"`
    63  		License     struct {
    64  			Name string `json:"name"`
    65  			URL  string `json:"url"`
    66  		} `json:"license"`
    67  		TermsOfService string `json:"termsOfService"`
    68  		Title          string `json:"title"`
    69  		Version        string `json:"version"`
    70  	} `json:"info"`
    71  	Paths    map[string]PathItemObject `json:"paths"`
    72  	Produces []string                  `json:"produces"`
    73  	Schemes  []string                  `json:"schemes"`
    74  	Swagger  string                    `json:"swagger"`
    75  }
    76  
    77  func (s *SwaggerAST) LoadFrom(r io.Reader) error {
    78  	return json.NewDecoder(r).Decode(&s)
    79  }
    80  
    81  func (s *SwaggerAST) ConvertIntoApiVersion(asMock bool) (apidef.VersionInfo, error) {
    82  	versionInfo := apidef.VersionInfo{}
    83  
    84  	if asMock {
    85  		return versionInfo, errors.New("Swagger mocks not supported")
    86  	}
    87  
    88  	versionInfo.UseExtendedPaths = true
    89  	versionInfo.Name = s.Info.Version
    90  	versionInfo.ExtendedPaths.TrackEndpoints = make([]apidef.TrackEndpointMeta, 0)
    91  
    92  	if len(s.Paths) == 0 {
    93  		return versionInfo, errors.New("no paths defined in swagger file")
    94  	}
    95  	for pathName, pathSpec := range s.Paths {
    96  		newEndpointMeta := apidef.TrackEndpointMeta{}
    97  		newEndpointMeta.Path = pathName
    98  
    99  		// We just want the paths here, no mocks
   100  		methods := map[string]PathMethodObject{
   101  			"GET":     pathSpec.Get,
   102  			"PUT":     pathSpec.Put,
   103  			"POST":    pathSpec.Post,
   104  			"HEAD":    pathSpec.Head,
   105  			"PATCH":   pathSpec.Patch,
   106  			"OPTIONS": pathSpec.Options,
   107  			"DELETE":  pathSpec.Delete,
   108  		}
   109  		for methodName, m := range methods {
   110  			// skip methods that are not defined
   111  			if len(m.Responses) == 0 && m.Description == "" && m.OperationID == "" {
   112  				continue
   113  			}
   114  
   115  			newEndpointMeta.Method = methodName
   116  			versionInfo.ExtendedPaths.TrackEndpoints = append(versionInfo.ExtendedPaths.TrackEndpoints, newEndpointMeta)
   117  		}
   118  	}
   119  
   120  	return versionInfo, nil
   121  }
   122  
   123  func (s *SwaggerAST) InsertIntoAPIDefinitionAsVersion(version apidef.VersionInfo, def *apidef.APIDefinition, versionName string) error {
   124  	def.VersionData.NotVersioned = false
   125  	def.VersionData.Versions[versionName] = version
   126  	return nil
   127  }
   128  
   129  func (s *SwaggerAST) ToAPIDefinition(orgId, upstreamURL string, as_mock bool) (*apidef.APIDefinition, error) {
   130  	ad := apidef.APIDefinition{
   131  		Name:             s.Info.Title,
   132  		Active:           true,
   133  		UseKeylessAccess: true,
   134  		APIID:            uuid.NewV4().String(),
   135  		OrgID:            orgId,
   136  	}
   137  	ad.VersionDefinition.Key = "version"
   138  	ad.VersionDefinition.Location = "header"
   139  	ad.VersionData.Versions = make(map[string]apidef.VersionInfo)
   140  	ad.Proxy.ListenPath = "/" + ad.APIID + "/"
   141  	ad.Proxy.StripListenPath = true
   142  	ad.Proxy.TargetURL = upstreamURL
   143  
   144  	if as_mock {
   145  		log.Warning("Mocks not supported for Swagger definitions, ignoring option")
   146  	}
   147  	versionData, err := s.ConvertIntoApiVersion(false)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	s.InsertIntoAPIDefinitionAsVersion(versionData, &ad, strings.Trim(s.Info.Version, " "))
   153  
   154  	return &ad, nil
   155  }