| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package openapi3 |
| |
| import ( |
| "fmt" |
| "reflect" |
| "strings" |
| "time" |
| |
| "github.com/getkin/kin-openapi/openapi3" |
| "github.com/pkg/errors" |
| |
| "github.com/apisix/manager-api/internal/core/entity" |
| "github.com/apisix/manager-api/internal/handler/data_loader/loader" |
| "github.com/apisix/manager-api/internal/utils/consts" |
| ) |
| |
| func (o Loader) Import(input interface{}) (*loader.DataSets, error) { |
| if input == nil { |
| panic("input is nil") |
| } |
| |
| d, ok := input.([]byte) |
| if !ok { |
| panic(fmt.Sprintf("input format error: expected []byte but it is %s", reflect.TypeOf(input).Kind().String())) |
| } |
| |
| // load OAS3 document |
| swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(d) |
| if err != nil { |
| return nil, err |
| } |
| |
| // no paths in OAS3 document |
| if len(swagger.Paths) <= 0 { |
| return nil, errors.Wrap(errors.New("OpenAPI documentation does not contain any paths"), consts.ErrImportFile.Error()) |
| } |
| |
| if o.TaskName == "" { |
| o.TaskName = "openapi_" + time.Now().Format("20060102150405") |
| } |
| |
| data, err := o.convertToEntities(swagger) |
| if err != nil { |
| return nil, err |
| } |
| |
| return data, nil |
| } |
| |
| func (o Loader) convertToEntities(s *openapi3.Swagger) (*loader.DataSets, error) { |
| var ( |
| // temporarily save the parsed data |
| data = &loader.DataSets{} |
| // global upstream ID |
| globalUpstreamID = o.TaskName |
| // global uri prefix |
| globalPath = "" |
| ) |
| |
| // create upstream when servers field not empty |
| if len(s.Servers) > 0 { |
| var upstream entity.Upstream |
| upstream = entity.Upstream{ |
| BaseInfo: entity.BaseInfo{ID: globalUpstreamID}, |
| UpstreamDef: entity.UpstreamDef{ |
| Name: globalUpstreamID, |
| Type: "roundrobin", |
| Nodes: map[string]float64{ |
| "0.0.0.0": 1, |
| }, |
| }, |
| } |
| data.Upstreams = append(data.Upstreams, upstream) |
| } |
| |
| // each one will correspond to a route |
| for uri, v := range s.Paths { |
| // replace parameter in uri to wildcard |
| realUri := regURIVar.ReplaceAllString(uri, "*") |
| // generate route Name |
| routeName := o.TaskName + "_" + strings.TrimPrefix(uri, "/") |
| |
| // decide whether to merge multi-method routes based on configuration |
| if o.MergeMethod { |
| // create a single route for each path, merge all methods |
| route := generateBaseRoute(routeName, v.Summary) |
| route.Uris = []string{globalPath + realUri} |
| route.UpstreamID = globalUpstreamID |
| for method := range v.Operations() { |
| route.Methods = append(route.Methods, strings.ToUpper(method)) |
| } |
| data.Routes = append(data.Routes, route) |
| } else { |
| // create routes for each method of each path |
| for method, operation := range v.Operations() { |
| subRouteID := routeName + "_" + method |
| route := generateBaseRoute(subRouteID, operation.Summary) |
| route.Uris = []string{globalPath + realUri} |
| route.Methods = []string{strings.ToUpper(method)} |
| route.UpstreamID = globalUpstreamID |
| data.Routes = append(data.Routes, route) |
| } |
| } |
| } |
| return data, nil |
| } |
| |
| // Generate a base route for customize |
| func generateBaseRoute(name string, desc string) entity.Route { |
| return entity.Route{ |
| Name: name, |
| Desc: desc, |
| Plugins: make(map[string]interface{}), |
| } |
| } |