You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by GitBox <gi...@apache.org> on 2020/12/23 02:24:08 UTC

[GitHub] [apisix-dashboard] Jaycean opened a new pull request #1102: Import & Export route from OpenAPI Specification3.0

Jaycean opened a new pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102


   Signed-off-by: Jacean <ji...@163.com>
   
   Import & Export route from OpenAPI Specification3.0
   
   - Why submit this pull request?
   - [ ] Bugfix
   - [x] New feature provided
   - [ ] Improve performance
   
   - Related issues
   issue: #825 
   ___
   ### New feature or improvement
   
   speed of progress:
   
   It has implemented the basic information and authentication plugins of OpenAPI configuration file: basic-auth, JWT-auth, key-auth; parameter authentication plugin, request-validation and request header parameter parsing.
   
   Remaining problems:
   
   When writing etcd for parameter verification, the system will report the following error because there are no upstream and service related parameters in OpenAPI.
   ```
   scheme validate fail: (root): Must validate at least one schema (anyOf)
   (root): plugins is required
   ```
   
   It is difficult to write to etcd in batch because it is necessary to verify the properties of upstream and service when writing data to etcd, and there is no relevant interface in the underlying layer.
   
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (4e06b76) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/1bdcaa8df2fe2fa6caba23809e69e26c5ad7902d?el=desc) (1bdcaa8) will **decrease** coverage by `19.95%`.
   > The diff coverage is `31.72%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   62.29%   42.33%   -19.96%     
   ===========================================
     Files          42       34        -8     
     Lines        2395     2258      -137     
   ===========================================
   - Hits         1492      956      -536     
   - Misses        722     1165      +443     
   + Partials      181      137       -44     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-62.50%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/utils/utils.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3V0aWxzL3V0aWxzLmdv) | `47.56% <0.00%> (-23.66%)` | :arrow_down: |
   | [api/internal/handler/data\_loader/import.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvZGF0YV9sb2FkZXIvaW1wb3J0Lmdv) | `29.96% <29.96%> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.52% <66.66%> (-20.87%)` | :arrow_down: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `81.81% <100.00%> (-4.26%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-74.49%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [30 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [1bdcaa8...4e06b76](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] starsz commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
starsz commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r564449030



##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))

Review comment:
       `/apisix/admin/import/routes` is better.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))
+	if err := req.ParseMultipartForm(int64(conf.ImportSizeLimit)); err != nil {
+		log.Warnf("upload file size exceeds limit: %s", err)
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	Force := req.URL.Query().Get("force")
+
+	_, fileHeader, err := req.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(fileHeader.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("required file type is .yaml, .yml or .json but got: %s", suffix)
+	}
+
+	// read file and parse
+	handle, err := fileHeader.Open()
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		err = handle.Close()
+	}()
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, fileHeader.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(swagger.Paths) < 1 {
+		return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+			errors.New("empty or invalid imported file")
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	// check route
+	for _, route := range routes {
+		err := checkRouteExist(c.Context(), h.routeStore, route)
+		if err != nil && Force != "1" {
+			log.Warnf("import duplicate: %s, route: %#v", err, route)
+			return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+		}
+		if route.ServiceID != nil {
+			_, err := h.svcStore.Get(c.Context(), utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := h.upstreamStore.Get(c.Context(), utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+
+		if _, err := h.routeStore.CreateCheck(route); err != nil {
+			return handler.SpecCodeResponse(err), err
+		}
+	}
+
+	// create route
+	for _, route := range routes {
+		if Force == "1" && route.ID != nil {
+			if _, err := h.routeStore.Update(c.Context(), route, true); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		} else {
+			if _, err := h.routeStore.Create(c.Context(), route); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		}
+	}
+
+	return nil, nil
+}
+
+func checkRouteExist(ctx context.Context, routeStore *store.GenericStore, route *entity.Route) error {
+	//routeStore := store.GetStore(store.HubKeyRoute)
+	ret, err := routeStore.List(ctx, store.ListInput{
+		Predicate: func(obj interface{}) bool {
+			id := utils.InterfaceToString(route.ID)
+			item := obj.(*entity.Route)
+			if id != "" && id != utils.InterfaceToString(item.ID) {
+				return false
+			}
+
+			if !(item.Host == route.Host && item.URI == route.URI && utils.StringSliceEqual(item.Uris, route.Uris) &&
+				utils.StringSliceEqual(item.RemoteAddrs, route.RemoteAddrs) && item.RemoteAddr == route.RemoteAddr &&
+				utils.StringSliceEqual(item.Hosts, route.Hosts) && item.Priority == route.Priority &&
+				utils.ValueEqual(item.Vars, route.Vars) && item.FilterFunc == route.FilterFunc) {
+				return false
+			}
+			return true
+		},
+		PageSize:   0,
+		PageNumber: 0,
+	})
+	if err != nil {
+		return err
+	}
+	if len(ret.Rows) > 0 {
+		return consts.InvalidParam("route is duplicate")
+	}
+	return nil
+}
+
+func parseExtension(val *openapi3.Operation) (*entity.Route, error) {
+	routeMap := map[string]interface{}{}
+	for key, val := range val.Extensions {
+		if strings.HasPrefix(key, "x-apisix-") {
+			routeMap[strings.TrimPrefix(key, "x-apisix-")] = val
+		}
+	}
+
+	route := new(entity.Route)
+	routeJson, err := json.Marshal(routeMap)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(routeJson, &route)
+	if err != nil {
+		return nil, err
+	}
+
+	return route, nil
+}
+
+type PathValue struct {
+	Method string
+	Value  *openapi3.Operation
+}
+
+func mergePathValue(key string, values []PathValue, swagger *openapi3.Swagger) (map[string]*entity.Route, error) {
+	var parsed []PathValue
+	var routes = map[string]*entity.Route{}
+	for _, value := range values {
+		value.Value.OperationID = strings.Replace(value.Value.OperationID, value.Method, "", 1)
+		var eq = false
+		for _, v := range parsed {
+			if utils.ValueEqual(v.Value, value.Value) {
+				eq = true
+				if routes[v.Method].Methods == nil {
+					routes[v.Method].Methods = []string{}
+				}
+				routes[v.Method].Methods = append(routes[v.Method].Methods, value.Method)
+			}
+		}
+		// not equal to the previous ones
+		if !eq {
+			route, err := getRouteFromPaths(value.Method, key, value.Value, swagger)
+			if err != nil {
+				return nil, err
+			}
+			routes[value.Method] = route
+			parsed = append(parsed, value)
+		}
+	}
+
+	return routes, nil
+}
+
+func OpenAPI3ToRoute(swagger *openapi3.Swagger) ([]*entity.Route, error) {
+	var routes []*entity.Route
+	paths := swagger.Paths
+	var upstream *entity.UpstreamDef
+	var err error
+	for k, v := range paths {
+		upstream = &entity.UpstreamDef{}
+		if up, ok := v.Extensions["x-apisix-upstream"]; ok {
+			err = json.Unmarshal(up.(json.RawMessage), upstream)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		var values []PathValue
+		if v.Get != nil {
+			value := PathValue{
+				Method: http.MethodGet,
+				Value:  v.Get,
+			}
+			values = append(values, value)
+		}
+		if v.Post != nil {
+			value := PathValue{
+				Method: http.MethodPost,
+				Value:  v.Post,
+			}
+			values = append(values, value)
+		}
+		if v.Head != nil {
+			value := PathValue{
+				Method: http.MethodHead,
+				Value:  v.Head,
+			}
+			values = append(values, value)
+		}
+		if v.Put != nil {
+			value := PathValue{
+				Method: http.MethodPut,
+				Value:  v.Put,
+			}
+			values = append(values, value)
+		}
+		if v.Patch != nil {
+			value := PathValue{
+				Method: http.MethodPatch,
+				Value:  v.Patch,
+			}
+			values = append(values, value)
+		}
+		if v.Delete != nil {
+			value := PathValue{
+				Method: http.MethodDelete,
+				Value:  v.Delete,
+			}
+			values = append(values, value)
+		}
+
+		// merge same route
+		tmp, err := mergePathValue(k, values, swagger)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, route := range tmp {
+			routes = append(routes, route)
+		}
+	}
+
+	return routes, nil
+}
+
+func parseParameters(parameters openapi3.Parameters, plugins map[string]interface{}) {
+	props := make(map[string]interface{})
+	var required []string
+	for _, v := range parameters {
+		if v.Value.Schema != nil {
+			v.Value.Schema.Value.Format = ""
+			v.Value.Schema.Value.XML = nil
+		}
+
+		switch v.Value.In {
+		case "header":
+			if v.Value.Schema != nil && v.Value.Schema.Value != nil {
+				props[v.Value.Name] = v.Value.Schema.Value
+			}
+			if v.Value.Required {
+				required = append(required, v.Value.Name)
+			}
+		}
+	}
+
+	requestValidation := make(map[string]interface{})
+	if rv, ok := plugins["request-validation"]; ok {
+		requestValidation = rv.(map[string]interface{})
+	}
+	requestValidation["header_schema"] = &entity.RequestValidation{
+		Type:       "object",
+		Required:   required,
+		Properties: props,
+	}
+	plugins["request-validation"] = requestValidation
+}
+
+func parseRequestBody(requestBody *openapi3.RequestBodyRef, swagger *openapi3.Swagger, plugins map[string]interface{}) {
+	schema := requestBody.Value.Content
+	requestValidation := make(map[string]interface{})
+	if rv, ok := plugins["request-validation"]; ok {
+		requestValidation = rv.(map[string]interface{})
+	}
+	for _, v := range schema {
+		if v.Schema.Ref != "" {
+			s := getParameters(v.Schema.Ref, &swagger.Components).Value
+			requestValidation["body_schema"] = &entity.RequestValidation{
+				Type:       s.Type,
+				Required:   s.Required,
+				Properties: s.Properties,
+			}
+			plugins["request-validation"] = requestValidation
+		} else if v.Schema.Value != nil {
+			if v.Schema.Value.Properties != nil {
+				for k1, v1 := range v.Schema.Value.Properties {
+					if v1.Ref != "" {
+						s := getParameters(v1.Ref, &swagger.Components)
+						v.Schema.Value.Properties[k1] = s
+					}
+					v1.Value.Format = ""
+				}
+				requestValidation["body_schema"] = &entity.RequestValidation{
+					Type:       v.Schema.Value.Type,
+					Required:   v.Schema.Value.Required,
+					Properties: v.Schema.Value.Properties,
+				}
+				plugins["request-validation"] = requestValidation
+			} else if v.Schema.Value.Items != nil {
+				if v.Schema.Value.Items.Ref != "" {
+					s := getParameters(v.Schema.Value.Items.Ref, &swagger.Components).Value
+					requestValidation["body_schema"] = &entity.RequestValidation{
+						Type:       s.Type,
+						Required:   s.Required,
+						Properties: s.Properties,
+					}
+					plugins["request-validation"] = requestValidation
+				}
+			} else {
+				requestValidation["body_schema"] = &entity.RequestValidation{
+					Type:       "object",
+					Required:   []string{},
+					Properties: v.Schema.Value.Properties,
+				}
+			}
+		}
+		plugins["request-validation"] = requestValidation
+	}
+}
+
+func parseSecurity(security openapi3.SecurityRequirements, securitySchemes openapi3.SecuritySchemes, plugins map[string]interface{}) {
+	// todo: import consumers
+	for _, securities := range security {
+		for name := range securities {
+			if schema, ok := securitySchemes[name]; ok {
+				value := schema.Value
+				if value == nil {
+					continue
+				}
+
+				// basic auth
+				if value.Type == "http" && value.Scheme == "basic" {
+					plugins["basic-auth"] = map[string]interface{}{}
+					//username, ok := value.Extensions["username"]
+					//if !ok {
+					//	continue
+					//}
+					//password, ok := value.Extensions["password"]
+					//if !ok {
+					//	continue
+					//}
+					//plugins["basic-auth"] = map[string]interface{}{
+					//	"username": username,
+					//	"password": password,
+					//}
+					// jwt auth
+				} else if value.Type == "http" && value.Scheme == "bearer" && value.BearerFormat == "JWT" {
+					plugins["jwt-auth"] = map[string]interface{}{}
+					//key, ok := value.Extensions["key"]
+					//if !ok {
+					//	continue
+					//}
+					//secret, ok := value.Extensions["secret"]
+					//if !ok {
+					//	continue
+					//}
+					//plugins["jwt-auth"] = map[string]interface{}{
+					//	"key":    key,
+					//	"secret": secret,
+					//}
+					// key auth
+				} else if value.Type == "apiKey" {
+					plugins["key-auth"] = map[string]interface{}{}
+					//key, ok := value.Extensions["key"]
+					//if !ok {
+					//	continue
+					//}
+					//plugins["key-auth"] = map[string]interface{}{
+					//	"key": key,
+					//}
+				}
+			}
+		}
+	}
+}
+
+func getRouteFromPaths(method, key string, value *openapi3.Operation, swagger *openapi3.Swagger) (*entity.Route, error) {
+	// transform /path/{var} to  /path/*
+	reg := regexp.MustCompile(`{[\w.]*}`)

Review comment:
       This can be put out of function.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))
+	if err := req.ParseMultipartForm(int64(conf.ImportSizeLimit)); err != nil {
+		log.Warnf("upload file size exceeds limit: %s", err)
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	Force := req.URL.Query().Get("force")
+
+	_, fileHeader, err := req.FormFile("file")
+	if err != nil {
+		return nil, err
+	}

Review comment:
       Ditto.

##########
File path: api/internal/route.go
##########
@@ -18,6 +18,7 @@ package internal
 
 import (
 	"fmt"
+	"github.com/apisix/manager-api/internal/handler/data_loader"

Review comment:
       Style.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))

Review comment:
       Droplet lib is supportting to read body now.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))
+	if err := req.ParseMultipartForm(int64(conf.ImportSizeLimit)); err != nil {
+		log.Warnf("upload file size exceeds limit: %s", err)
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	Force := req.URL.Query().Get("force")
+
+	_, fileHeader, err := req.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(fileHeader.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("required file type is .yaml, .yml or .json but got: %s", suffix)
+	}
+
+	// read file and parse
+	handle, err := fileHeader.Open()
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		err = handle.Close()
+	}()
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, fileHeader.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(swagger.Paths) < 1 {
+		return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+			errors.New("empty or invalid imported file")
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	// check route
+	for _, route := range routes {
+		err := checkRouteExist(c.Context(), h.routeStore, route)
+		if err != nil && Force != "1" {
+			log.Warnf("import duplicate: %s, route: %#v", err, route)
+			return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+		}
+		if route.ServiceID != nil {
+			_, err := h.svcStore.Get(c.Context(), utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := h.upstreamStore.Get(c.Context(), utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+
+		if _, err := h.routeStore.CreateCheck(route); err != nil {
+			return handler.SpecCodeResponse(err), err
+		}

Review comment:
       Enrich the return info.

##########
File path: api/internal/handler/route/route.go
##########
@@ -259,7 +259,7 @@ func (h *Handler) List(c droplet.Context) (interface{}, error) {
 	return ret, nil
 }
 
-func generateLuaCode(script map[string]interface{}) (string, error) {
+func GenerateLuaCode(script map[string]interface{}) (string, error) {

Review comment:
       This can be rollback.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))
+	if err := req.ParseMultipartForm(int64(conf.ImportSizeLimit)); err != nil {
+		log.Warnf("upload file size exceeds limit: %s", err)
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	Force := req.URL.Query().Get("force")
+
+	_, fileHeader, err := req.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(fileHeader.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("required file type is .yaml, .yml or .json but got: %s", suffix)
+	}
+
+	// read file and parse
+	handle, err := fileHeader.Open()
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		err = handle.Close()
+	}()
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, fileHeader.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(swagger.Paths) < 1 {
+		return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+			errors.New("empty or invalid imported file")
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	// check route
+	for _, route := range routes {
+		err := checkRouteExist(c.Context(), h.routeStore, route)
+		if err != nil && Force != "1" {
+			log.Warnf("import duplicate: %s, route: %#v", err, route)
+			return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+		}
+		if route.ServiceID != nil {
+			_, err := h.svcStore.Get(c.Context(), utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := h.upstreamStore.Get(c.Context(), utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+
+		if _, err := h.routeStore.CreateCheck(route); err != nil {
+			return handler.SpecCodeResponse(err), err
+		}
+	}
+
+	// create route
+	for _, route := range routes {
+		if Force == "1" && route.ID != nil {
+			if _, err := h.routeStore.Update(c.Context(), route, true); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		} else {
+			if _, err := h.routeStore.Create(c.Context(), route); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		}
+	}
+
+	return nil, nil

Review comment:
       TODO: return the sum info.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))
+	if err := req.ParseMultipartForm(int64(conf.ImportSizeLimit)); err != nil {
+		log.Warnf("upload file size exceeds limit: %s", err)
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	Force := req.URL.Query().Get("force")
+
+	_, fileHeader, err := req.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(fileHeader.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("required file type is .yaml, .yml or .json but got: %s", suffix)
+	}
+
+	// read file and parse
+	handle, err := fileHeader.Open()
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		err = handle.Close()
+	}()
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, fileHeader.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(swagger.Paths) < 1 {
+		return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+			errors.New("empty or invalid imported file")
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	// check route
+	for _, route := range routes {
+		err := checkRouteExist(c.Context(), h.routeStore, route)
+		if err != nil && Force != "1" {
+			log.Warnf("import duplicate: %s, route: %#v", err, route)
+			return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+		}
+		if route.ServiceID != nil {
+			_, err := h.svcStore.Get(c.Context(), utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := h.upstreamStore.Get(c.Context(), utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+
+		if _, err := h.routeStore.CreateCheck(route); err != nil {
+			return handler.SpecCodeResponse(err), err
+		}
+	}
+
+	// create route
+	for _, route := range routes {
+		if Force == "1" && route.ID != nil {
+			if _, err := h.routeStore.Update(c.Context(), route, true); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		} else {
+			if _, err := h.routeStore.Create(c.Context(), route); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		}
+	}
+
+	return nil, nil
+}
+
+func checkRouteExist(ctx context.Context, routeStore *store.GenericStore, route *entity.Route) error {
+	//routeStore := store.GetStore(store.HubKeyRoute)
+	ret, err := routeStore.List(ctx, store.ListInput{
+		Predicate: func(obj interface{}) bool {
+			id := utils.InterfaceToString(route.ID)
+			item := obj.(*entity.Route)
+			if id != "" && id != utils.InterfaceToString(item.ID) {
+				return false
+			}
+
+			if !(item.Host == route.Host && item.URI == route.URI && utils.StringSliceEqual(item.Uris, route.Uris) &&
+				utils.StringSliceEqual(item.RemoteAddrs, route.RemoteAddrs) && item.RemoteAddr == route.RemoteAddr &&
+				utils.StringSliceEqual(item.Hosts, route.Hosts) && item.Priority == route.Priority &&
+				utils.ValueEqual(item.Vars, route.Vars) && item.FilterFunc == route.FilterFunc) {
+				return false
+			}
+			return true
+		},
+		PageSize:   0,
+		PageNumber: 0,
+	})
+	if err != nil {
+		return err
+	}
+	if len(ret.Rows) > 0 {
+		return consts.InvalidParam("route is duplicate")
+	}
+	return nil
+}
+
+func parseExtension(val *openapi3.Operation) (*entity.Route, error) {
+	routeMap := map[string]interface{}{}
+	for key, val := range val.Extensions {
+		if strings.HasPrefix(key, "x-apisix-") {
+			routeMap[strings.TrimPrefix(key, "x-apisix-")] = val
+		}
+	}
+
+	route := new(entity.Route)
+	routeJson, err := json.Marshal(routeMap)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(routeJson, &route)
+	if err != nil {
+		return nil, err
+	}
+
+	return route, nil
+}
+
+type PathValue struct {
+	Method string
+	Value  *openapi3.Operation
+}
+
+func mergePathValue(key string, values []PathValue, swagger *openapi3.Swagger) (map[string]*entity.Route, error) {
+	var parsed []PathValue
+	var routes = map[string]*entity.Route{}
+	for _, value := range values {
+		value.Value.OperationID = strings.Replace(value.Value.OperationID, value.Method, "", 1)
+		var eq = false
+		for _, v := range parsed {
+			if utils.ValueEqual(v.Value, value.Value) {
+				eq = true
+				if routes[v.Method].Methods == nil {
+					routes[v.Method].Methods = []string{}
+				}
+				routes[v.Method].Methods = append(routes[v.Method].Methods, value.Method)
+			}
+		}
+		// not equal to the previous ones
+		if !eq {
+			route, err := getRouteFromPaths(value.Method, key, value.Value, swagger)
+			if err != nil {
+				return nil, err
+			}
+			routes[value.Method] = route
+			parsed = append(parsed, value)
+		}
+	}
+
+	return routes, nil
+}
+
+func OpenAPI3ToRoute(swagger *openapi3.Swagger) ([]*entity.Route, error) {
+	var routes []*entity.Route
+	paths := swagger.Paths
+	var upstream *entity.UpstreamDef
+	var err error
+	for k, v := range paths {
+		upstream = &entity.UpstreamDef{}
+		if up, ok := v.Extensions["x-apisix-upstream"]; ok {
+			err = json.Unmarshal(up.(json.RawMessage), upstream)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		var values []PathValue
+		if v.Get != nil {
+			value := PathValue{
+				Method: http.MethodGet,
+				Value:  v.Get,
+			}
+			values = append(values, value)
+		}
+		if v.Post != nil {
+			value := PathValue{
+				Method: http.MethodPost,
+				Value:  v.Post,
+			}
+			values = append(values, value)
+		}
+		if v.Head != nil {
+			value := PathValue{
+				Method: http.MethodHead,
+				Value:  v.Head,
+			}
+			values = append(values, value)
+		}
+		if v.Put != nil {
+			value := PathValue{
+				Method: http.MethodPut,
+				Value:  v.Put,
+			}
+			values = append(values, value)
+		}
+		if v.Patch != nil {
+			value := PathValue{
+				Method: http.MethodPatch,
+				Value:  v.Patch,
+			}
+			values = append(values, value)
+		}
+		if v.Delete != nil {
+			value := PathValue{
+				Method: http.MethodDelete,
+				Value:  v.Delete,
+			}
+			values = append(values, value)
+		}
+
+		// merge same route
+		tmp, err := mergePathValue(k, values, swagger)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, route := range tmp {
+			routes = append(routes, route)
+		}
+	}
+
+	return routes, nil
+}
+
+func parseParameters(parameters openapi3.Parameters, plugins map[string]interface{}) {
+	props := make(map[string]interface{})
+	var required []string
+	for _, v := range parameters {
+		if v.Value.Schema != nil {
+			v.Value.Schema.Value.Format = ""
+			v.Value.Schema.Value.XML = nil
+		}
+
+		switch v.Value.In {
+		case "header":
+			if v.Value.Schema != nil && v.Value.Schema.Value != nil {
+				props[v.Value.Name] = v.Value.Schema.Value
+			}
+			if v.Value.Required {
+				required = append(required, v.Value.Name)
+			}
+		}
+	}
+
+	requestValidation := make(map[string]interface{})
+	if rv, ok := plugins["request-validation"]; ok {
+		requestValidation = rv.(map[string]interface{})
+	}
+	requestValidation["header_schema"] = &entity.RequestValidation{
+		Type:       "object",
+		Required:   required,
+		Properties: props,
+	}
+	plugins["request-validation"] = requestValidation
+}
+
+func parseRequestBody(requestBody *openapi3.RequestBodyRef, swagger *openapi3.Swagger, plugins map[string]interface{}) {
+	schema := requestBody.Value.Content
+	requestValidation := make(map[string]interface{})
+	if rv, ok := plugins["request-validation"]; ok {
+		requestValidation = rv.(map[string]interface{})
+	}
+	for _, v := range schema {
+		if v.Schema.Ref != "" {
+			s := getParameters(v.Schema.Ref, &swagger.Components).Value
+			requestValidation["body_schema"] = &entity.RequestValidation{
+				Type:       s.Type,
+				Required:   s.Required,
+				Properties: s.Properties,
+			}
+			plugins["request-validation"] = requestValidation
+		} else if v.Schema.Value != nil {
+			if v.Schema.Value.Properties != nil {
+				for k1, v1 := range v.Schema.Value.Properties {
+					if v1.Ref != "" {
+						s := getParameters(v1.Ref, &swagger.Components)
+						v.Schema.Value.Properties[k1] = s
+					}
+					v1.Value.Format = ""
+				}
+				requestValidation["body_schema"] = &entity.RequestValidation{
+					Type:       v.Schema.Value.Type,
+					Required:   v.Schema.Value.Required,
+					Properties: v.Schema.Value.Properties,
+				}
+				plugins["request-validation"] = requestValidation
+			} else if v.Schema.Value.Items != nil {
+				if v.Schema.Value.Items.Ref != "" {
+					s := getParameters(v.Schema.Value.Items.Ref, &swagger.Components).Value
+					requestValidation["body_schema"] = &entity.RequestValidation{
+						Type:       s.Type,
+						Required:   s.Required,
+						Properties: s.Properties,
+					}
+					plugins["request-validation"] = requestValidation
+				}
+			} else {
+				requestValidation["body_schema"] = &entity.RequestValidation{
+					Type:       "object",
+					Required:   []string{},
+					Properties: v.Schema.Value.Properties,
+				}
+			}
+		}

Review comment:
       Need to remove the suffix.

##########
File path: api/test/e2e/http.go
##########
@@ -0,0 +1,106 @@
+/*
+ * 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 e2e
+
+import (
+	"bytes"
+	"encoding/json"
+	"io"
+	"io/ioutil"
+	"mime/multipart"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+type UploadFile struct {
+	Name     string
+	Filepath string
+}
+
+var httpClient = &http.Client{}
+
+func PostFile(reqUrl string, reqParams map[string]string, files []UploadFile, headers map[string]string) string {
+	return post(reqUrl, reqParams, "multipart/form-data", files, headers)
+}
+
+func post(reqUrl string, reqParams map[string]string, contentType string, files []UploadFile, headers map[string]string) string {
+	requestBody, realContentType := getReader(reqParams, contentType, files)
+	httpRequest, _ := http.NewRequest("POST", reqUrl, requestBody)
+	httpRequest.Header.Add("Content-Type", realContentType)
+	if headers != nil {
+		for k, v := range headers {
+			httpRequest.Header.Add(k, v)
+		}
+	}
+	resp, err := httpClient.Do(httpRequest)
+
+	defer func() {
+		err = resp.Body.Close()

Review comment:
       Need to make sure.

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,531 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/data"
+	"github.com/shiningrush/droplet/middleware"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/log"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    *store.GenericStore
+	svcStore      store.Interface
+	upstreamStore store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", wgin.Wraps(h.Import))
+}
+
+type ImportInput struct {
+	Force bool `auto_read:"force,query"`
+}
+
+func (h *Handler) Import(c droplet.Context) (interface{}, error) {
+	httpReq := c.Get(middleware.KeyHttpRequest)
+	if httpReq == nil {
+		return nil, errors.New("input middleware cannot get http request")
+	}
+	req := httpReq.(*http.Request)
+	req.Body = http.MaxBytesReader(nil, req.Body, int64(conf.ImportSizeLimit))
+	if err := req.ParseMultipartForm(int64(conf.ImportSizeLimit)); err != nil {
+		log.Warnf("upload file size exceeds limit: %s", err)
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	Force := req.URL.Query().Get("force")
+
+	_, fileHeader, err := req.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(fileHeader.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("required file type is .yaml, .yml or .json but got: %s", suffix)
+	}
+
+	// read file and parse
+	handle, err := fileHeader.Open()
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		err = handle.Close()
+	}()
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, fileHeader.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(swagger.Paths) < 1 {
+		return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+			errors.New("empty or invalid imported file")
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	// check route
+	for _, route := range routes {
+		err := checkRouteExist(c.Context(), h.routeStore, route)
+		if err != nil && Force != "1" {
+			log.Warnf("import duplicate: %s, route: %#v", err, route)
+			return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+		}
+		if route.ServiceID != nil {
+			_, err := h.svcStore.Get(c.Context(), utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := h.upstreamStore.Get(c.Context(), utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+
+		if _, err := h.routeStore.CreateCheck(route); err != nil {
+			return handler.SpecCodeResponse(err), err
+		}
+	}
+
+	// create route
+	for _, route := range routes {
+		if Force == "1" && route.ID != nil {
+			if _, err := h.routeStore.Update(c.Context(), route, true); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		} else {
+			if _, err := h.routeStore.Create(c.Context(), route); err != nil {
+				return handler.SpecCodeResponse(err), err
+			}
+		}
+	}
+
+	return nil, nil
+}
+
+func checkRouteExist(ctx context.Context, routeStore *store.GenericStore, route *entity.Route) error {
+	//routeStore := store.GetStore(store.HubKeyRoute)
+	ret, err := routeStore.List(ctx, store.ListInput{
+		Predicate: func(obj interface{}) bool {
+			id := utils.InterfaceToString(route.ID)
+			item := obj.(*entity.Route)
+			if id != "" && id != utils.InterfaceToString(item.ID) {
+				return false
+			}
+
+			if !(item.Host == route.Host && item.URI == route.URI && utils.StringSliceEqual(item.Uris, route.Uris) &&
+				utils.StringSliceEqual(item.RemoteAddrs, route.RemoteAddrs) && item.RemoteAddr == route.RemoteAddr &&
+				utils.StringSliceEqual(item.Hosts, route.Hosts) && item.Priority == route.Priority &&
+				utils.ValueEqual(item.Vars, route.Vars) && item.FilterFunc == route.FilterFunc) {
+				return false
+			}
+			return true
+		},
+		PageSize:   0,
+		PageNumber: 0,
+	})
+	if err != nil {
+		return err
+	}
+	if len(ret.Rows) > 0 {
+		return consts.InvalidParam("route is duplicate")
+	}
+	return nil
+}
+
+func parseExtension(val *openapi3.Operation) (*entity.Route, error) {
+	routeMap := map[string]interface{}{}
+	for key, val := range val.Extensions {
+		if strings.HasPrefix(key, "x-apisix-") {
+			routeMap[strings.TrimPrefix(key, "x-apisix-")] = val
+		}
+	}
+
+	route := new(entity.Route)
+	routeJson, err := json.Marshal(routeMap)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(routeJson, &route)
+	if err != nil {
+		return nil, err
+	}
+
+	return route, nil
+}
+
+type PathValue struct {
+	Method string
+	Value  *openapi3.Operation
+}
+
+func mergePathValue(key string, values []PathValue, swagger *openapi3.Swagger) (map[string]*entity.Route, error) {
+	var parsed []PathValue
+	var routes = map[string]*entity.Route{}
+	for _, value := range values {
+		value.Value.OperationID = strings.Replace(value.Value.OperationID, value.Method, "", 1)
+		var eq = false
+		for _, v := range parsed {
+			if utils.ValueEqual(v.Value, value.Value) {
+				eq = true
+				if routes[v.Method].Methods == nil {
+					routes[v.Method].Methods = []string{}
+				}
+				routes[v.Method].Methods = append(routes[v.Method].Methods, value.Method)
+			}
+		}
+		// not equal to the previous ones
+		if !eq {
+			route, err := getRouteFromPaths(value.Method, key, value.Value, swagger)
+			if err != nil {
+				return nil, err
+			}
+			routes[value.Method] = route
+			parsed = append(parsed, value)
+		}
+	}
+
+	return routes, nil
+}
+
+func OpenAPI3ToRoute(swagger *openapi3.Swagger) ([]*entity.Route, error) {
+	var routes []*entity.Route
+	paths := swagger.Paths
+	var upstream *entity.UpstreamDef
+	var err error
+	for k, v := range paths {
+		upstream = &entity.UpstreamDef{}
+		if up, ok := v.Extensions["x-apisix-upstream"]; ok {
+			err = json.Unmarshal(up.(json.RawMessage), upstream)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		var values []PathValue
+		if v.Get != nil {
+			value := PathValue{
+				Method: http.MethodGet,
+				Value:  v.Get,
+			}
+			values = append(values, value)
+		}
+		if v.Post != nil {
+			value := PathValue{
+				Method: http.MethodPost,
+				Value:  v.Post,
+			}
+			values = append(values, value)
+		}
+		if v.Head != nil {
+			value := PathValue{
+				Method: http.MethodHead,
+				Value:  v.Head,
+			}
+			values = append(values, value)
+		}
+		if v.Put != nil {
+			value := PathValue{
+				Method: http.MethodPut,
+				Value:  v.Put,
+			}
+			values = append(values, value)
+		}
+		if v.Patch != nil {
+			value := PathValue{
+				Method: http.MethodPatch,
+				Value:  v.Patch,
+			}
+			values = append(values, value)
+		}
+		if v.Delete != nil {
+			value := PathValue{
+				Method: http.MethodDelete,
+				Value:  v.Delete,
+			}
+			values = append(values, value)
+		}
+
+		// merge same route
+		tmp, err := mergePathValue(k, values, swagger)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, route := range tmp {
+			routes = append(routes, route)
+		}
+	}
+
+	return routes, nil
+}
+
+func parseParameters(parameters openapi3.Parameters, plugins map[string]interface{}) {
+	props := make(map[string]interface{})
+	var required []string
+	for _, v := range parameters {
+		if v.Value.Schema != nil {
+			v.Value.Schema.Value.Format = ""
+			v.Value.Schema.Value.XML = nil
+		}
+
+		switch v.Value.In {
+		case "header":
+			if v.Value.Schema != nil && v.Value.Schema.Value != nil {
+				props[v.Value.Name] = v.Value.Schema.Value
+			}
+			if v.Value.Required {
+				required = append(required, v.Value.Name)
+			}
+		}
+	}
+
+	requestValidation := make(map[string]interface{})
+	if rv, ok := plugins["request-validation"]; ok {
+		requestValidation = rv.(map[string]interface{})
+	}
+	requestValidation["header_schema"] = &entity.RequestValidation{
+		Type:       "object",
+		Required:   required,
+		Properties: props,
+	}
+	plugins["request-validation"] = requestValidation
+}
+
+func parseRequestBody(requestBody *openapi3.RequestBodyRef, swagger *openapi3.Swagger, plugins map[string]interface{}) {
+	schema := requestBody.Value.Content
+	requestValidation := make(map[string]interface{})
+	if rv, ok := plugins["request-validation"]; ok {
+		requestValidation = rv.(map[string]interface{})
+	}
+	for _, v := range schema {
+		if v.Schema.Ref != "" {
+			s := getParameters(v.Schema.Ref, &swagger.Components).Value
+			requestValidation["body_schema"] = &entity.RequestValidation{
+				Type:       s.Type,
+				Required:   s.Required,
+				Properties: s.Properties,
+			}
+			plugins["request-validation"] = requestValidation
+		} else if v.Schema.Value != nil {
+			if v.Schema.Value.Properties != nil {
+				for k1, v1 := range v.Schema.Value.Properties {
+					if v1.Ref != "" {
+						s := getParameters(v1.Ref, &swagger.Components)
+						v.Schema.Value.Properties[k1] = s
+					}
+					v1.Value.Format = ""
+				}
+				requestValidation["body_schema"] = &entity.RequestValidation{
+					Type:       v.Schema.Value.Type,
+					Required:   v.Schema.Value.Required,
+					Properties: v.Schema.Value.Properties,
+				}
+				plugins["request-validation"] = requestValidation
+			} else if v.Schema.Value.Items != nil {
+				if v.Schema.Value.Items.Ref != "" {
+					s := getParameters(v.Schema.Value.Items.Ref, &swagger.Components).Value
+					requestValidation["body_schema"] = &entity.RequestValidation{
+						Type:       s.Type,
+						Required:   s.Required,
+						Properties: s.Properties,
+					}
+					plugins["request-validation"] = requestValidation
+				}
+			} else {
+				requestValidation["body_schema"] = &entity.RequestValidation{
+					Type:       "object",
+					Required:   []string{},
+					Properties: v.Schema.Value.Properties,
+				}
+			}
+		}
+		plugins["request-validation"] = requestValidation
+	}
+}
+
+func parseSecurity(security openapi3.SecurityRequirements, securitySchemes openapi3.SecuritySchemes, plugins map[string]interface{}) {
+	// todo: import consumers
+	for _, securities := range security {
+		for name := range securities {
+			if schema, ok := securitySchemes[name]; ok {
+				value := schema.Value
+				if value == nil {
+					continue
+				}
+
+				// basic auth
+				if value.Type == "http" && value.Scheme == "basic" {
+					plugins["basic-auth"] = map[string]interface{}{}
+					//username, ok := value.Extensions["username"]
+					//if !ok {
+					//	continue
+					//}
+					//password, ok := value.Extensions["password"]
+					//if !ok {
+					//	continue
+					//}
+					//plugins["basic-auth"] = map[string]interface{}{
+					//	"username": username,
+					//	"password": password,
+					//}
+					// jwt auth
+				} else if value.Type == "http" && value.Scheme == "bearer" && value.BearerFormat == "JWT" {
+					plugins["jwt-auth"] = map[string]interface{}{}
+					//key, ok := value.Extensions["key"]
+					//if !ok {
+					//	continue
+					//}
+					//secret, ok := value.Extensions["secret"]
+					//if !ok {
+					//	continue
+					//}
+					//plugins["jwt-auth"] = map[string]interface{}{
+					//	"key":    key,
+					//	"secret": secret,
+					//}
+					// key auth
+				} else if value.Type == "apiKey" {
+					plugins["key-auth"] = map[string]interface{}{}
+					//key, ok := value.Extensions["key"]
+					//if !ok {
+					//	continue
+					//}
+					//plugins["key-auth"] = map[string]interface{}{
+					//	"key": key,
+					//}
+				}
+			}
+		}
+	}
+}
+
+func getRouteFromPaths(method, key string, value *openapi3.Operation, swagger *openapi3.Swagger) (*entity.Route, error) {
+	// transform /path/{var} to  /path/*
+	reg := regexp.MustCompile(`{[\w.]*}`)
+	foundStr := reg.FindString(key)
+	if foundStr != "" {
+		key = strings.Split(key, foundStr)[0] + "*"
+	}
+
+	route, err := parseExtension(value)
+	if err != nil {
+		return nil, err
+	}
+
+	route.URI = key

Review comment:
       Should be put in to URIs.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r555511815



##########
File path: api/test/e2e/import_test.go
##########
@@ -0,0 +1,238 @@
+/*
+ * 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 e2e
+
+import (
+	"github.com/stretchr/testify/assert"
+	"github.com/tidwall/gjson"
+	"io/ioutil"
+	"net/http"
+	"path/filepath"
+	"testing"
+)
+
+func TestImport_default(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test-default.yaml")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	tests = append(tests, HttpTestCase{
+		Desc:         "verify the route just imported",
+		Object:       APISIXExpect(t),
+		Method:       http.MethodGet,
+		Path:         "/hello",
+		ExpectStatus: http.StatusOK,
+		ExpectBody:   "hello world",
+		Sleep:        sleepTime,
+	})
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}
+
+func TestImport_json(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test.json")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	tests = append(tests, HttpTestCase{
+		Desc:         "verify the route just imported",
+		Object:       APISIXExpect(t),
+		Method:       http.MethodGet,
+		Path:         "/hello",
+		ExpectStatus: http.StatusOK,
+		ExpectBody:   "hello world",
+		Sleep:        sleepTime,
+	})
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}
+
+func TestImport_with_plugins(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test-plugins.yaml")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	verifyTests := []HttpTestCase{
+		{
+			Desc:         "verify the route just imported",
+			Object:       APISIXExpect(t),
+			Method:       http.MethodPost,
+			Path:         "/hello",
+			Body:         `{}`,
+			ExpectStatus: http.StatusBadRequest,
+			ExpectBody:   `property "status" is required`,
+			Sleep:        sleepTime,
+		},
+		{
+			Desc:         "verify the route just imported",
+			Object:       APISIXExpect(t),
+			Method:       http.MethodPost,
+			Path:         "/hello",
+			Body:         `{"status": "1"}`,
+			ExpectStatus: http.StatusUnauthorized,
+			ExpectBody:   `{"message":"Missing authorization in request"}`,
+			Sleep:        sleepTime,
+		},
+	}
+	tests = append(tests, verifyTests...)
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}

Review comment:
       while debugging Fe, I found the file below could also be imported, It would be better to add a test case to cover the wrong file.
   ```yaml
   #
   # 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.
   #
   
   conf:
     listen:
       host: 127.0.0.1     # `manager api` listening ip or host name
       port: 9000          # `manager api` listening port
     etcd:
       endpoints:          # supports defining multiple etcd host addresses for an etcd cluster
         - 127.0.0.1:2379
                             # yamllint disable rule:comments-indentation
                             # etcd basic auth info
       # username: "root"    # ignore etcd username if not enable etcd auth
       # password: "123456"  # ignore etcd password if not enable etcd auth
     log:
       error_log:
         level: warn       # supports levels, lower to higher: debug, info, warn, error, panic, fatal
         file_path:
           logs/error.log  # supports relative path, absolute path, standard output
                           # such as: logs/error.log, /tmp/logs/error.log, /dev/stdout, /dev/stderr
       access_log:
         file_path:
           logs/access.log  # supports relative path, absolute path, standard output
                            # such as: logs/access.log, /tmp/logs/access.log, /dev/stdout, /dev/stderr
                            # log example: 2020-12-09T16:38:09.039+0800	INFO	filter/logging.go:46	/apisix/admin/routes/r1	{"status": 401, "host": "127.0.0.1:9000", "query": "asdfsafd=adf&a=a", "requestId": "3d50ecb8-758c-46d1-af5b-cd9d1c820156", "latency": 0, "remoteIP": "127.0.0.1", "method": "PUT", "errs": []}
   authentication:
     secret:
       secret              # secret for jwt token generation.
                           # NOTE: Highly recommended to modify this value to protect `manager api`.
                           # if it's default value, when `manager api` start , it will generate a random string to replace it.
     expire_time: 3600     # jwt token expire time, in second
     users:                # yamllint enable rule:comments-indentation
       - username: admin   # username and password for login `manager api`
         password: admin
       - username: user
         password: user
   
   ```
   




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r555161547



##########
File path: api/test/testdata/import-test-plugins.yaml
##########
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+# If you want to set the specified configuration value, you can set the new
+# in this file. For example if you want to specify the etcd address:
+#
+consumes:
+- application/json
+- application/xml
+components:
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+      username: test
+      password: testp
+info:
+  description: |-
+    test desc
+  license:
+    name: Apache License 2.0
+    url: http://www.apache.org/licenses/LICENSE-2.0
+  title: |-
+    test title
+paths:
+  /hello:    
+    post:
+      x-api-limit: 20
+      description: |-
+        hello world.
+      operationId: hello
+      x-apisix-upstream:
+        type: roundrobin
+        nodes:
+          - host: "172.16.238.20"
+            port: 1980
+            weight: 1
+      parameters:
+      - name: id
+        in: header
+        description: ID of pet to use
+        required: true
+        schema:
+          type: array
+          items:
+            type: string
+        style: simple
+
+      requestBody:
+        content:
+          'application/x-www-form-urlencoded':
+            schema:
+              properties:
+                  name: 
+                    description: Updated name of the pet
+                    type: string
+                  status:
+                    description: Updated status of the pet
+                    type: string
+              required:
+                - status
+
+      produces:
+      - application/json
+
+      security:
+      - basicAuth: []
+
+      responses:
+        "0":
+          description: list response
+          schema:
+            items:
+              $ref: '#/definitions/service'
+            type: array
+        default:
+          description: unexpected error
+          schema:
+            $ref: '#/definitions/ApiError'
+produces:
+- application/json
+- application/xml
+schemes:
+- http
+- https
+swagger: "2.0"

Review comment:
       I noticed that  the version of this test file is swagger is 2.0, and our basic version of this issue is OAS3.0, which equals to swagger 3.0. As far as I know, there are some difference between the these versions, so I just want to make sure that is the current feature compatible with two versions of file or just for 2.0?
   
   For the export feature in #1245 is only for 3.0 now, baseline alignment is necessary.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764442783


   Do we need to add **test cases** about 
   
   1. import a error file
   2. a file includes two or more APIs


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (4e06b76) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/1bdcaa8df2fe2fa6caba23809e69e26c5ad7902d?el=desc) (1bdcaa8) will **decrease** coverage by `19.95%`.
   > The diff coverage is `31.72%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   62.29%   42.33%   -19.96%     
   ===========================================
     Files          42       34        -8     
     Lines        2395     2258      -137     
   ===========================================
   - Hits         1492      956      -536     
   - Misses        722     1165      +443     
   + Partials      181      137       -44     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-62.50%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/utils/utils.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3V0aWxzL3V0aWxzLmdv) | `47.56% <0.00%> (-23.66%)` | :arrow_down: |
   | [api/internal/handler/data\_loader/import.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvZGF0YV9sb2FkZXIvaW1wb3J0Lmdv) | `29.96% <29.96%> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.52% <66.66%> (-20.87%)` | :arrow_down: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `81.81% <100.00%> (-4.26%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-74.49%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [30 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [1bdcaa8...4e06b76](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-759184568


   > > > before we import new route data, do we need to clean the old route first?
   > > 
   > > 
   > > I think that the original data should not be modified, and the status of the imported route should be `offline`.
   > 
   > agree with the `offline` status, and do we consider letting the user choose whether to override it or not? that may be more flexible
   
   I feel that there is a certain risk in overriding, and I don't think it is necessary to do so. Waiting for the opinions of others. .
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] juzhiyuan commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
juzhiyuan commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764448583


   > Do we need to add **test cases** about
   > 
   > 1. import a error file
   > 2. a file includes two or more APIs
   
   Yep


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] juzhiyuan commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
juzhiyuan commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-760885133


   > For example, how can I change my folder to your folder name 'data loader'.
   
   Couldn't get your point 🤣 just to make sure, do you mean if we could keep those 2 files at the same folder?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] tokers commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
tokers commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-760951330


   @Jaycean Conflicts should be resolved firstly :)


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764442783


   Do we need to add **test cases** about 
   
   1. import a error file
   2. a file includes two or more APIs


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-759145529


   > before we import new route data, do we need to clean the old route first?
   
   I think that the original data should not be modified, and the status of the imported route should be `offline`.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (9576e27) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/81dbdbfd639610b653f9ac7ed95c559aa890c5e3?el=desc) (81dbdbf) will **decrease** coverage by `18.87%`.
   > The diff coverage is `41.17%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   63.13%   44.25%   -18.88%     
   ===========================================
     Files          41       32        -9     
     Lines        2360     1986      -374     
   ===========================================
   - Hits         1490      879      -611     
   - Misses        695      996      +301     
   + Partials      175      111       -64     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-62.50%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/utils/utils.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3V0aWxzL3V0aWxzLmdv) | `47.56% <0.00%> (-23.66%)` | :arrow_down: |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.52% <66.66%> (-20.87%)` | :arrow_down: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `81.81% <81.81%> (-5.84%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-74.49%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [27 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [81dbdbf...9576e27](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-760798891


   Hi, the two functions of import and export are closely related, so I want to discuss the name of the folder with you. I personally think that the two files are ultimately in one folder. For example, how can I change my folder to your folder name 'data loader'. I wonder if you have any good suggestions


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-762555156


   > > Hi, the two functions of import and export are closely related, so I want to discuss the name of the folder with you. I personally think that the two files are ultimately in one folder. For example, how can I change my folder to your folder name 'data loader'. I wonder if you have any good suggestions
   > 
   > how about we use the same folder name `data_loader` ? just rename your folder.
   
   Now I change my folder name, and there is a problem of package reference, but if I change my package to 'data_loader', I don't think the description of my function is accurate, so I'll discuss it with you. Because the folder contains import and export functions, we can change the folder to 'data_operation' Do you have any other good suggestions?
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (c1a6a1c) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/61f7c210baa21c65f0fa46dc0f1301ee96ccd7a5?el=desc) (61f7c21) will **increase** coverage by `0.29%`.
   > The diff coverage is `81.81%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   + Coverage   42.44%   42.73%   +0.29%     
   ==========================================
     Files          31       31              
     Lines        1932     1942      +10     
   ==========================================
   + Hits          820      830      +10     
     Misses       1001     1001              
     Partials      111      111              
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (ø)` | |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `43.43% <66.66%> (ø)` | |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.33% <80.00%> (+0.70%)` | :arrow_up: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `80.83% <85.71%> (+0.83%)` | :arrow_up: |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [61f7c21...c1a6a1c](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-760890023


   > Hi, the two functions of import and export are closely related, so I want to discuss the name of the folder with you. I personally think that the two files are ultimately in one folder. For example, how can I change my folder to your folder name 'data loader'. I wonder if you have any good suggestions
   
   how about we use the same folder name `data_loader` ? just rename your folder.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-761918967


   > > Hi, the two functions of import and export are closely related, so I want to discuss the name of the folder with you. I personally think that the two files are ultimately in one folder. For example, how can I change my folder to your folder name 'data loader'. I wonder if you have any good suggestions
   > 
   > how about we use the same folder name `data_loader` ? just rename your folder.
   
   no problem.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-765366914


   > Do we need to add a test case about a route with as many props as possible
   
   sure


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r556206018



##########
File path: api/test/testdata/import-test-plugins.yaml
##########
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+# If you want to set the specified configuration value, you can set the new
+# in this file. For example if you want to specify the etcd address:
+#
+consumes:
+- application/json
+- application/xml
+components:
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+      username: test
+      password: testp
+info:
+  description: |-
+    test desc
+  license:
+    name: Apache License 2.0
+    url: http://www.apache.org/licenses/LICENSE-2.0
+  title: |-
+    test title
+paths:
+  /hello:    
+    post:
+      x-api-limit: 20
+      description: |-
+        hello world.
+      operationId: hello
+      x-apisix-upstream:
+        type: roundrobin
+        nodes:
+          - host: "172.16.238.20"
+            port: 1980
+            weight: 1
+      parameters:
+      - name: id
+        in: header
+        description: ID of pet to use
+        required: true
+        schema:
+          type: array
+          items:
+            type: string
+        style: simple
+
+      requestBody:
+        content:
+          'application/x-www-form-urlencoded':
+            schema:
+              properties:
+                  name: 
+                    description: Updated name of the pet
+                    type: string
+                  status:
+                    description: Updated status of the pet
+                    type: string
+              required:
+                - status
+
+      produces:
+      - application/json
+
+      security:
+      - basicAuth: []
+
+      responses:
+        "0":
+          description: list response
+          schema:
+            items:
+              $ref: '#/definitions/service'
+            type: array
+        default:
+          description: unexpected error
+          schema:
+            $ref: '#/definitions/ApiError'
+produces:
+- application/json
+- application/xml
+schemes:
+- http
+- https
+swagger: "2.0"

Review comment:
       fixed.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-759148662


   > > before we import new route data, do we need to clean the old route first?
   > 
   > I think that the original data should not be modified, and the status of the imported route should be `offline`.
   
   agree with the `offline` status, and do we consider letting the user choose whether to override it or not? that may be more flexible


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] tokers commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
tokers commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r557885773



##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,468 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet/data"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	routeHandler "github.com/apisix/manager-api/internal/handler/route"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    store.Interface
+	svcStore      store.Interface
+	upstreamStore store.Interface
+	scriptStore   store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+		scriptStore:   store.GetStore(store.HubKeyScript),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", consts.ErrorWrapper(Import))
+}
+
+func Import(c *gin.Context) (interface{}, error) {
+	file, err := c.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(file.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("the file type error: %s", suffix)
+	}
+	if file.Size > int64(conf.ImportSizeLimit) {
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	// read file and parse
+	handle, err := file.Open()
+	defer func() {
+		err = handle.Close()
+	}()
+	if err != nil {
+		return nil, err
+	}
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, file.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	routeStore := store.GetStore(store.HubKeyRoute)
+	upstreamStore := store.GetStore(store.HubKeyUpstream)
+	scriptStore := store.GetStore(store.HubKeyScript)
+
+	// check route
+	for _, route := range routes {
+		_, err := checkRouteName(route.Name)
+		if err != nil {
+			continue
+		}
+		if route.ServiceID != nil {
+			_, err := routeStore.Get(utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := upstreamStore.Get(utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.Script != nil {
+			if route.ID == "" {
+				route.ID = utils.GetFlakeUidStr()
+			}
+			script := &entity.Script{}
+			script.ID = utils.InterfaceToString(route.ID)
+			script.Script = route.Script

Review comment:
       ```suggestion
   			script := &entity.Script{
   			    ID: utils.InterfaceToString(route.ID),
   			    Script: route.Script,
   			}
   ```

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,468 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet/data"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	routeHandler "github.com/apisix/manager-api/internal/handler/route"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    store.Interface
+	svcStore      store.Interface
+	upstreamStore store.Interface
+	scriptStore   store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+		scriptStore:   store.GetStore(store.HubKeyScript),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", consts.ErrorWrapper(Import))
+}
+
+func Import(c *gin.Context) (interface{}, error) {
+	file, err := c.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(file.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("the file type error: %s", suffix)
+	}
+	if file.Size > int64(conf.ImportSizeLimit) {
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	// read file and parse
+	handle, err := file.Open()
+	defer func() {

Review comment:
       Should check `err` before the `defer` call.

##########
File path: api/internal/core/store/validate.go
##########
@@ -243,6 +245,8 @@ func (v *APISIXJsonSchemaValidator) Validate(obj interface{}) error {
 			}
 			errString.AppendString(vErr.String())
 		}
+		j, _ := json.Marshal(obj)
+		log.Errorf("schema validate failed:s: %v, obj: %s", v.schemaDef, string(j))

Review comment:
       Why not just using `%#v` to show the object?

##########
File path: api/internal/handler/data_loader/import.go
##########
@@ -0,0 +1,468 @@
+/*
+ * 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 data_loader
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet/data"
+
+	"github.com/apisix/manager-api/internal/conf"
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/internal/handler"
+	routeHandler "github.com/apisix/manager-api/internal/handler/route"
+	"github.com/apisix/manager-api/internal/utils"
+	"github.com/apisix/manager-api/internal/utils/consts"
+)
+
+type Handler struct {
+	routeStore    store.Interface
+	svcStore      store.Interface
+	upstreamStore store.Interface
+	scriptStore   store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{
+		routeStore:    store.GetStore(store.HubKeyRoute),
+		svcStore:      store.GetStore(store.HubKeyService),
+		upstreamStore: store.GetStore(store.HubKeyUpstream),
+		scriptStore:   store.GetStore(store.HubKeyScript),
+	}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/import", consts.ErrorWrapper(Import))
+}
+
+func Import(c *gin.Context) (interface{}, error) {
+	file, err := c.FormFile("file")
+	if err != nil {
+		return nil, err
+	}
+
+	// file check
+	suffix := path.Ext(file.Filename)
+	if suffix != ".json" && suffix != ".yaml" && suffix != ".yml" {
+		return nil, fmt.Errorf("the file type error: %s", suffix)
+	}
+	if file.Size > int64(conf.ImportSizeLimit) {
+		return nil, fmt.Errorf("the file size exceeds the limit; limit %d", conf.ImportSizeLimit)
+	}
+
+	// read file and parse
+	handle, err := file.Open()
+	defer func() {
+		err = handle.Close()
+	}()
+	if err != nil {
+		return nil, err
+	}
+
+	reader := bufio.NewReader(handle)
+	bytes := make([]byte, file.Size)
+	_, err = reader.Read(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	routes, err := OpenAPI3ToRoute(swagger)
+	if err != nil {
+		return nil, err
+	}
+
+	routeStore := store.GetStore(store.HubKeyRoute)
+	upstreamStore := store.GetStore(store.HubKeyUpstream)
+	scriptStore := store.GetStore(store.HubKeyScript)
+
+	// check route
+	for _, route := range routes {
+		_, err := checkRouteName(route.Name)
+		if err != nil {
+			continue
+		}
+		if route.ServiceID != nil {
+			_, err := routeStore.Get(utils.InterfaceToString(route.ServiceID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("service id: %s not found", route.ServiceID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.UpstreamID != nil {
+			_, err := upstreamStore.Get(utils.InterfaceToString(route.UpstreamID))
+			if err != nil {
+				if err == data.ErrNotFound {
+					return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+						fmt.Errorf("upstream id: %s not found", route.UpstreamID)
+				}
+				return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest}, err
+			}
+		}
+		if route.Script != nil {
+			if route.ID == "" {
+				route.ID = utils.GetFlakeUidStr()
+			}
+			script := &entity.Script{}
+			script.ID = utils.InterfaceToString(route.ID)
+			script.Script = route.Script
+			// to lua
+			var err error
+			route.Script, err = routeHandler.GenerateLuaCode(route.Script.(map[string]interface{}))
+			if err != nil {
+				return nil, err
+			}
+			// save original conf
+			if err = scriptStore.Create(c, script); err != nil {
+				return nil, err
+			}
+		}
+
+		if _, err := routeStore.CreateCheck(route); err != nil {
+			return handler.SpecCodeResponse(err), err
+		}
+	}
+
+	// create route
+	for _, route := range routes {
+		if err := routeStore.Create(c, route); err != nil {
+			println(err.Error())

Review comment:
       Debugging code?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (f370f54) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/754f5598706fe5dfe9a09bf0d51d0701406c692c?el=desc) (754f559) will **increase** coverage by `0.23%`.
   > The diff coverage is `88.88%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   + Coverage   44.19%   44.43%   +0.23%     
   ==========================================
     Files          31       31              
     Lines        1948     1958      +10     
   ==========================================
   + Hits          861      870       +9     
   - Misses        975      976       +1     
     Partials      112      112              
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (ø)` | |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.49% <66.66%> (ø)` | |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.33% <80.00%> (+0.70%)` | :arrow_up: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `79.76% <100.00%> (+0.25%)` | :arrow_up: |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [754f559...f370f54](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-765343958


   Do we need to add a test case about a route  with as many props as possible?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] membphis commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
membphis commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-759181507


   > how about giving the choice to users? e.g: Add a param to deside whether to cover the old routes or return a error, which tells users that they already have the same routes.
   
   I think this is a good way. we can implement the first version: `return error` ^_^


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (0e71f3b) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/754f5598706fe5dfe9a09bf0d51d0701406c692c?el=desc) (754f559) will **increase** coverage by `0.25%`.
   > The diff coverage is `88.23%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   + Coverage   44.19%   44.45%   +0.25%     
   ==========================================
     Files          31       31              
     Lines        1948     1957       +9     
   ==========================================
   + Hits          861      870       +9     
     Misses        975      975              
     Partials      112      112              
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (ø)` | |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.49% <66.66%> (ø)` | |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (+0.47%)` | :arrow_up: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `80.35% <100.00%> (+0.85%)` | :arrow_up: |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [754f559...0e71f3b](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (1caeb35) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/81dbdbfd639610b653f9ac7ed95c559aa890c5e3?el=desc) (81dbdbf) will **decrease** coverage by `18.56%`.
   > The diff coverage is `72.22%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   63.13%   44.56%   -18.57%     
   ===========================================
     Files          41       32        -9     
     Lines        2360     1970      -390     
   ===========================================
   - Hits         1490      878      -612     
   - Misses        695      981      +286     
   + Partials      175      111       -64     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-62.50%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.52% <66.66%> (-20.87%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `81.21% <72.72%> (-6.45%)` | :arrow_down: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-74.49%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [26 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [81dbdbf...1caeb35](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (1de6730) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/61f7c210baa21c65f0fa46dc0f1301ee96ccd7a5?el=desc) (61f7c21) will **increase** coverage by `0.24%`.
   > The diff coverage is `81.81%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   + Coverage   42.44%   42.68%   +0.24%     
   ==========================================
     Files          31       31              
     Lines        1932     1942      +10     
   ==========================================
   + Hits          820      829       +9     
   - Misses       1001     1002       +1     
     Partials      111      111              
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (ø)` | |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `43.43% <66.66%> (ø)` | |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.33% <80.00%> (+0.70%)` | :arrow_up: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `80.23% <85.71%> (+0.23%)` | :arrow_up: |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [61f7c21...1de6730](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r561648621



##########
File path: api/test/e2e/import_test.go
##########
@@ -0,0 +1,248 @@
+/*
+ * 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 e2e
+
+import (
+	"github.com/stretchr/testify/assert"
+	"github.com/tidwall/gjson"
+	"io/ioutil"
+	"net/http"
+	"path/filepath"
+	"testing"
+	"time"
+)
+
+func TestImport_default(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test-default.yaml")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	// sleep for data sync
+	time.Sleep(sleepTime)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	tests = append(tests, HttpTestCase{
+		Desc:         "verify the route just imported",
+		Object:       APISIXExpect(t),
+		Method:       http.MethodGet,
+		Path:         "/hello",
+		ExpectStatus: http.StatusOK,
+		ExpectBody:   "hello world",
+		Sleep:        sleepTime,
+	})
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}
+
+func TestImport_json(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test.json")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	// sleep for data sync
+	time.Sleep(sleepTime)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	tests = append(tests, HttpTestCase{
+		Desc:         "verify the route just imported",
+		Object:       APISIXExpect(t),
+		Method:       http.MethodGet,
+		Path:         "/hello",
+		ExpectStatus: http.StatusOK,
+		ExpectBody:   "hello world",
+		Sleep:        sleepTime,
+	})
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}
+
+func TestImport_with_plugins(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test-plugins.yaml")

Review comment:
       I have a question @nic-chen 
   It seems that the API in this file includes a required header params `id`(/testdata/import-test-plugins.yaml L48-57), but the route imported from this file did not  has header params validation. 




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764209076


   > @nic-chen Hi, the CI of your PR has not been passed. You need to rebase the master branch, and the get list method of store needs to add the `context` parameter
   
   thanks for remind.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-768155965


   ping @starsz @imjoey @Jaycean  for review, thanks


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (be06fbc) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/6d7f11a14c84c4f918827ae5f24befaf02bf681f?el=desc) (6d7f11a) will **decrease** coverage by `1.02%`.
   > The diff coverage is `46.61%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   - Coverage   62.79%   61.77%   -1.03%     
   ==========================================
     Files          41       42       +1     
     Lines        2352     2595     +243     
   ==========================================
   + Hits         1477     1603     +126     
   - Misses        700      787      +87     
   - Partials      175      205      +30     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/conf/conf.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvbmYvY29uZi5nbw==) | `67.85% <ø> (ø)` | |
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `81.25% <ø> (+18.75%)` | :arrow_up: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `55.46% <ø> (ø)` | |
   | [api/internal/handler/data\_loader/import.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvZGF0YV9sb2FkZXIvaW1wb3J0Lmdv) | `43.34% <43.34%> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `68.26% <66.66%> (+0.86%)` | :arrow_up: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `69.27% <75.00%> (+0.34%)` | :arrow_up: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `88.62% <100.00%> (+0.49%)` | :arrow_up: |
   | [api/internal/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3JvdXRlLmdv) | `84.37% <100.00%> (+0.50%)` | :arrow_up: |
   | [api/internal/core/storage/etcd.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmFnZS9ldGNkLmdv) | `44.94% <0.00%> (-2.25%)` | :arrow_down: |
   | ... and [6 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [6d7f11a...be06fbc](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764194110


   @nic-chen Hi, the CI of your PR has not been passed. You need to rebase the master branch, and the get list method of store needs to add the `context` parameter


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (a47ef38) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/6d7f11a14c84c4f918827ae5f24befaf02bf681f?el=desc) (6d7f11a) will **decrease** coverage by `1.06%`.
   > The diff coverage is `46.61%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   - Coverage   62.79%   61.73%   -1.07%     
   ==========================================
     Files          41       42       +1     
     Lines        2352     2595     +243     
   ==========================================
   + Hits         1477     1602     +125     
   - Misses        700      791      +91     
   - Partials      175      202      +27     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/conf/conf.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvbmYvY29uZi5nbw==) | `67.85% <ø> (ø)` | |
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `81.25% <ø> (+18.75%)` | :arrow_up: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `55.46% <ø> (ø)` | |
   | [api/internal/handler/data\_loader/import.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvZGF0YV9sb2FkZXIvaW1wb3J0Lmdv) | `43.34% <43.34%> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `68.26% <66.66%> (+0.86%)` | :arrow_up: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `69.27% <75.00%> (+0.34%)` | :arrow_up: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `88.62% <100.00%> (+0.49%)` | :arrow_up: |
   | [api/internal/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3JvdXRlLmdv) | `84.37% <100.00%> (+0.50%)` | :arrow_up: |
   | [api/cmd/managerapi.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2NtZC9tYW5hZ2VyYXBpLmdv) | `70.83% <0.00%> (-6.25%)` | :arrow_down: |
   | [api/internal/utils/closer.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3V0aWxzL2Nsb3Nlci5nbw==) | `33.33% <0.00%> (ø)` | |
   | ... and [7 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [6d7f11a...a47ef38](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r561648621



##########
File path: api/test/e2e/import_test.go
##########
@@ -0,0 +1,248 @@
+/*
+ * 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 e2e
+
+import (
+	"github.com/stretchr/testify/assert"
+	"github.com/tidwall/gjson"
+	"io/ioutil"
+	"net/http"
+	"path/filepath"
+	"testing"
+	"time"
+)
+
+func TestImport_default(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test-default.yaml")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	// sleep for data sync
+	time.Sleep(sleepTime)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	tests = append(tests, HttpTestCase{
+		Desc:         "verify the route just imported",
+		Object:       APISIXExpect(t),
+		Method:       http.MethodGet,
+		Path:         "/hello",
+		ExpectStatus: http.StatusOK,
+		ExpectBody:   "hello world",
+		Sleep:        sleepTime,
+	})
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}
+
+func TestImport_json(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test.json")
+	assert.Nil(t, err)
+
+	headers := map[string]string{
+		"Authorization": token,
+	}
+	files := []UploadFile{
+		{Name: "file", Filepath: path},
+	}
+	PostFile(ManagerAPIHost+"/apisix/admin/import", nil, files, headers)
+
+	// sleep for data sync
+	time.Sleep(sleepTime)
+
+	request, _ := http.NewRequest("GET", ManagerAPIHost+"/apisix/admin/routes", nil)
+	request.Header.Add("Authorization", token)
+	resp, err := http.DefaultClient.Do(request)
+	assert.Nil(t, err)
+	defer resp.Body.Close()
+	respBody, _ := ioutil.ReadAll(resp.Body)
+	list := gjson.Get(string(respBody), "data.rows").Value().([]interface{})
+
+	var tests []HttpTestCase
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "route patch for update status(online)",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Body:         `{"status":1}`,
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+			Sleep:        sleepTime,
+		}
+		tests = append(tests, tc)
+	}
+
+	// verify route
+	tests = append(tests, HttpTestCase{
+		Desc:         "verify the route just imported",
+		Object:       APISIXExpect(t),
+		Method:       http.MethodGet,
+		Path:         "/hello",
+		ExpectStatus: http.StatusOK,
+		ExpectBody:   "hello world",
+		Sleep:        sleepTime,
+	})
+
+	// delete test data
+	for _, item := range list {
+		route := item.(map[string]interface{})
+		tc := HttpTestCase{
+			Desc:         "delete route",
+			Object:       ManagerApiExpect(t),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/" + route["id"].(string),
+			Headers:      map[string]string{"Authorization": token},
+			ExpectStatus: http.StatusOK,
+		}
+		tests = append(tests, tc)
+	}
+
+	for _, tc := range tests {
+		testCaseCheck(tc, t)
+	}
+}
+
+func TestImport_with_plugins(t *testing.T) {
+	path, err := filepath.Abs("../testdata/import-test-plugins.yaml")

Review comment:
       I have a question @nic-chen 
   It seems that the API in this file includes a required header params `id`(/testdata/import-test-plugins.yaml L48-57), but the route imported from this file did not  has header params validation. 




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] juzhiyuan commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
juzhiyuan commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r559947748



##########
File path: api/test/testdata/import-test-plugins.yaml
##########
@@ -61,17 +61,17 @@ paths:
           'application/x-www-form-urlencoded':
             schema:
               properties:
-                  name: 
-                    description: Updated name of the pet
-                    type: string
-                  status:
-                    description: Updated status of the pet
-                    type: string
+                name:
+                  description: Updated name of the pet

Review comment:
       ```suggestion
                     description: Update pet's name
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io commented on pull request #1102: Import & Export route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (17b356c) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/3d14164e276eb3c846888f0c2fb4f264f950c816?el=desc) (3d14164) will **decrease** coverage by `3.78%`.
   > The diff coverage is `0.00%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   - Coverage   42.30%   38.52%   -3.79%     
   ==========================================
     Files          31       31              
     Lines        1924     2113     +189     
   ==========================================
     Hits          814      814              
   - Misses       1000     1189     +189     
     Partials      110      110              
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `23.03% <0.00%> (-19.89%)` | :arrow_down: |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [3d14164...17b356c](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764209076


   > @nic-chen Hi, the CI of your PR has not been passed. You need to rebase the master branch, and the get list method of store needs to add the `context` parameter
   
   thanks for remind.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] imjoey commented on a change in pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
imjoey commented on a change in pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#discussion_r565160065



##########
File path: api/internal/conf/conf.go
##########
@@ -52,6 +52,7 @@ var (
 	UserList         = make(map[string]User, 2)
 	AuthConf         Authentication
 	SSLDefaultStatus = 1 //enable ssl by default
+	ImportSizeLimit  = 10 * 1024 * 1024

Review comment:
       Is the unit `bytes`? It would be better for clear comments.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] juzhiyuan commented on pull request #1102: Import & Export route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
juzhiyuan commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-751658690


   Any update about this feature?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-768166641


   Thanks for @nic-chen and all reviewers, pr megerd


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import & Export route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752830445


   > Any update about this feature?
   
   After communicated with @nic-chen , he  will continue doing import on current pr, and @Jaycean will go on doing export route on another pr, and it is planed to be ready later next week. 
   
   cc @juzhiyuan 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-759148972


   https://github.com/apache/apisix-dashboard/pull/1102/checks?check_run_id=1686825100
   
   another unstable fe e2e test case, cc @LiteSun 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848






----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (8c6ffa9) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/9cb9aa7354d6daf231af689c80e3ca79234a0605?el=desc) (9cb9aa7) will **decrease** coverage by `21.64%`.
   > The diff coverage is `29.13%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   65.42%   43.77%   -21.65%     
   ===========================================
     Files          43       35        -8     
     Lines        2655     2508      -147     
   ===========================================
   - Hits         1737     1098      -639     
   - Misses        713     1253      +540     
   + Partials      205      157       -48     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-81.25%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/utils/utils.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL3V0aWxzL3V0aWxzLmdv) | `47.56% <0.00%> (-23.66%)` | :arrow_down: |
   | [api/internal/handler/data\_loader/route\_import.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvZGF0YV9sb2FkZXIvcm91dGVfaW1wb3J0Lmdv) | `27.41% <27.41%> (ø)` | |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `81.81% <100.00%> (-4.26%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-70.41%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [34 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [9cb9aa7...8c6ffa9](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-758287503


   > before we import new route data, do we need to clean the old route first?
   
   how about giving the choice to users? e.g: Add a param to deside whether to cover the old routes or  return a error, which tells users that they already have the same routes.
   
   BTW,  I just want to make sure what is the matching strategy of the apisix when there are two or more same routes?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] nic-chen commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
nic-chen commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-762577575


   > > > Hi, the two functions of import and export are closely related, so I want to discuss the name of the folder with you. I personally think that the two files are ultimately in one folder. For example, how can I change my folder to your folder name 'data loader'. I wonder if you have any good suggestions
   > > 
   > > 
   > > how about we use the same folder name `data_loader` ? just rename your folder.
   > 
   > Now I change my folder name, and there is a problem of package reference, but if I change my package to 'data_loader', I don't think the description of my function is accurate, so I'll discuss it with you. Because the folder contains import and export functions, we can change the folder to 'data_operation' Do you have any other good suggestions?
   
   loader can load and unload stuff, I think is OK for us..
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764194110


   @nic-chen Hi, the CI of your PR has not been passed. You need to rebase the master branch, and the get list method of store needs to add the `context` parameter


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (be06fbc) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/6d7f11a14c84c4f918827ae5f24befaf02bf681f?el=desc) (6d7f11a) will **decrease** coverage by `18.22%`.
   > The diff coverage is `88.23%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   62.79%   44.57%   -18.23%     
   ===========================================
     Files          41       32        -9     
     Lines        2352     1972      -380     
   ===========================================
   - Hits         1477      879      -598     
   - Misses        700      981      +281     
   + Partials      175      112       -63     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-62.50%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.52% <66.66%> (-20.87%)` | :arrow_down: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `80.83% <100.00%> (-7.29%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-70.41%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [26 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [6d7f11a...be06fbc](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (a47ef38) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/6d7f11a14c84c4f918827ae5f24befaf02bf681f?el=desc) (6d7f11a) will **decrease** coverage by `18.22%`.
   > The diff coverage is `88.23%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@             Coverage Diff             @@
   ##           master    #1102       +/-   ##
   ===========================================
   - Coverage   62.79%   44.57%   -18.23%     
   ===========================================
     Files          41       32        -9     
     Lines        2352     1972      -380     
   ===========================================
   - Hits         1477      879      -598     
   - Misses        700      981      +281     
   + Partials      175      112       -63     
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (-62.50%)` | :arrow_down: |
   | [api/internal/filter/schema.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9zY2hlbWEuZ28=) | `0.00% <ø> (-55.47%)` | :arrow_down: |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `46.52% <66.66%> (-20.87%)` | :arrow_down: |
   | [api/internal/core/store/validate.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvdmFsaWRhdGUuZ28=) | `58.10% <75.00%> (-10.83%)` | :arrow_down: |
   | [api/internal/core/store/store.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmUuZ28=) | `80.83% <100.00%> (-7.29%)` | :arrow_down: |
   | [api/internal/filter/request\_id.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9yZXF1ZXN0X2lkLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
   | [api/internal/core/store/storehub.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvc3RvcmUvc3RvcmVodWIuZ28=) | `0.00% <0.00%> (-70.41%)` | :arrow_down: |
   | [api/internal/filter/cors.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2ZpbHRlci9jb3JzLmdv) | `0.00% <0.00%> (-66.67%)` | :arrow_down: |
   | ... and [26 more](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree-more) | |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [6d7f11a...a47ef38](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] juzhiyuan commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
juzhiyuan commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-764448583


   > Do we need to add **test cases** about
   > 
   > 1. import a error file
   > 2. a file includes two or more APIs
   
   Yep


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] membphis commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
membphis commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-758014961


   before we import new route data, do we need to clean the old route first?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-762579150


   > > > > Hi, the two functions of import and export are closely related, so I want to discuss the name of the folder with you. I personally think that the two files are ultimately in one folder. For example, how can I change my folder to your folder name 'data loader'. I wonder if you have any good suggestions
   > > > 
   > > > 
   > > > how about we use the same folder name `data_loader` ? just rename your folder.
   > > 
   > > 
   > > Now I change my folder name, and there is a problem of package reference, but if I change my package to 'data_loader', I don't think the description of my function is accurate, so I'll discuss it with you. Because the folder contains import and export functions, we can change the folder to 'data_operation' Do you have any other good suggestions?
   > 
   > loader can load and unload stuff, I think is OK for us..
   
   OK, no problem.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] Jaycean commented on pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
Jaycean commented on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-760622249


   > > > > before we import new route data, do we need to clean the old route first?
   > > > 
   > > > 
   > > > I think that the original data should not be modified, and the status of the imported route should be `offline`.
   > > 
   > > 
   > > agree with the `offline` status, and do we consider letting the user choose whether to override it or not? that may be more flexible
   > 
   > I feel that there is a certain risk in overriding, and I don't think it is necessary to do so. Waiting for the opinions of others. .
   
   I think the front end can directly ask the user whether the same data is covered when importing. If it is covered, the front end will pass a parameter to the back end, such as `is_covered` (of course, the default is false).


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] codecov-io edited a comment on pull request #1102: feat: import & Export route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
codecov-io edited a comment on pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102#issuecomment-752030848


   # [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=h1) Report
   > Merging [#1102](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=desc) (e04fc9a) into [master](https://codecov.io/gh/apache/apisix-dashboard/commit/c0241ee83450e2f26695aed12dbb17d6f9da59d3?el=desc) (c0241ee) will **decrease** coverage by `3.78%`.
   > The diff coverage is `0.00%`.
   
   [![Impacted file tree graph](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/graphs/tree.svg?width=650&height=150&src=pr&token=Q1HERXN96P)](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree)
   
   ```diff
   @@            Coverage Diff             @@
   ##           master    #1102      +/-   ##
   ==========================================
   - Coverage   42.38%   38.60%   -3.79%     
   ==========================================
     Files          31       31              
     Lines        1930     2119     +189     
   ==========================================
     Hits          818      818              
   - Misses       1001     1190     +189     
     Partials      111      111              
   ```
   
   
   | [Impacted Files](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=tree) | Coverage Δ | |
   |---|---|---|
   | [api/internal/core/entity/entity.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2NvcmUvZW50aXR5L2VudGl0eS5nbw==) | `0.00% <ø> (ø)` | |
   | [api/internal/handler/route/route.go](https://codecov.io/gh/apache/apisix-dashboard/pull/1102/diff?src=pr&el=tree#diff-YXBpL2ludGVybmFsL2hhbmRsZXIvcm91dGUvcm91dGUuZ28=) | `23.03% <0.00%> (-19.89%)` | :arrow_down: |
   
   ------
   
   [Continue to review full report at Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=continue).
   > **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
   > `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
   > Powered by [Codecov](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=footer). Last update [c0241ee...e04fc9a](https://codecov.io/gh/apache/apisix-dashboard/pull/1102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [apisix-dashboard] liuxiran merged pull request #1102: feat: import route from OpenAPI Specification3.0

Posted by GitBox <gi...@apache.org>.
liuxiran merged pull request #1102:
URL: https://github.com/apache/apisix-dashboard/pull/1102


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org