You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2020/10/15 02:04:35 UTC

[apisix-dashboard] branch refactor updated: feature: refactor plugin api and auth api (#556)

This is an automated email from the ASF dual-hosted git repository.

juzhiyuan pushed a commit to branch refactor
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/refactor by this push:
     new 03d39f8  feature: refactor plugin api and auth api (#556)
03d39f8 is described below

commit 03d39f8490adb3e6762c567e9733152fa1c68752
Author: nic-chen <33...@users.noreply.github.com>
AuthorDate: Thu Oct 15 10:04:27 2020 +0800

    feature: refactor plugin api and auth api (#556)
    
    * feat: refactor plugin and healthy api
    
    * feat: refactor authentication api
    
    * fix: remove useless files
    
    * chore: update json schema
    
    * test: add login test
    
    * test: add test for plugin
    
    * fix: license
---
 api/conf/conf.go                                   |  40 +-
 api/conf/schema.json                               |   2 +-
 api/errno/error.go                                 | 170 ------
 api/filter/authentication.go                       |  24 +-
 api/filter/logging.go                              |   5 +-
 .../handler/authentication/authentication.go       |  78 +++
 .../handler/authentication/authentication_test.go  |  67 +++
 api/internal/handler/handler.go                    |   4 +-
 api/{route => internal/handler/healthz}/healthz.go |  28 +-
 api/internal/handler/plugin/plugin.go              |  65 +++
 .../handler/plugin/plugin_test.go}                 |  70 +--
 api/{route/base.go => internal/route.go}           |  18 +-
 api/main.go                                        |   8 +-
 api/route/authentication.go                        |  68 ---
 api/route/authentication_test.go                   |  52 --
 api/route/consumer.go                              | 143 -----
 api/route/consumer_test.go                         |  88 ---
 api/route/plugin.go                                |  59 --
 api/route/route.go                                 | 572 ------------------
 api/route/route_group.go                           | 233 --------
 api/route/route_test.go                            | 195 -------
 api/route/ssl.go                                   | 197 -------
 api/route/ssl_test.go                              |  65 ---
 api/route/upstream.go                              | 384 ------------
 api/script/db/schema.sql                           |  71 ---
 api/service/base.go                                |  49 --
 api/service/consumer.go                            | 349 -----------
 api/service/plugin.go                              |  62 --
 api/service/route.go                               | 647 ---------------------
 api/service/route_group.go                         | 155 -----
 api/service/ssl.go                                 | 589 -------------------
 api/service/upstream.go                            | 271 ---------
 api/utils/copy.go                                  |  41 --
 api/utils/http.go                                  | 114 ----
 34 files changed, 319 insertions(+), 4664 deletions(-)

diff --git a/api/conf/conf.go b/api/conf/conf.go
index bda5bdb..66079b5 100644
--- a/api/conf/conf.go
+++ b/api/conf/conf.go
@@ -19,6 +19,7 @@ package conf
 import (
 	"fmt"
 	"io/ioutil"
+	"math/rand"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -137,23 +138,36 @@ func initApisix() {
 	}
 }
 
+func randomString(n int) string {
+	var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+	b := make([]rune, n)
+	for i := range b {
+		b[i] = letters[rand.Intn(len(letters))]
+	}
+	return string(b)
+}
+
 func initAuthentication() {
 	filePath := configurationPath()
-	if configurationContent, err := ioutil.ReadFile(filePath); err != nil {
+	configurationContent, err := ioutil.ReadFile(filePath)
+	if err != nil {
 		panic(fmt.Sprintf("fail to read configuration: %s", filePath))
-	} else {
-		configuration := gjson.ParseBytes(configurationContent)
-		userList := configuration.Get("authentication.user").Array()
-
-		// create user list
-		for _, item := range userList {
-			username := item.Map()["username"].String()
-			password := item.Map()["password"].String()
-			UserList[item.Map()["username"].String()] = user{Username: username, Password: password}
-		}
-		AuthenticationConfig.Session.Secret = configuration.Get("authentication.session.secret").String()
-		AuthenticationConfig.Session.ExpireTime = configuration.Get("authentication.session.expireTime").Uint()
 	}
+
+	configuration := gjson.ParseBytes(configurationContent)
+	userList := configuration.Get("authentication.user").Array()
+	// create user list
+	for _, item := range userList {
+		username := item.Map()["username"].String()
+		password := item.Map()["password"].String()
+		UserList[item.Map()["username"].String()] = user{Username: username, Password: password}
+	}
+	AuthenticationConfig.Session.Secret = configuration.Get("authentication.session.secret").String()
+	if "secret" == AuthenticationConfig.Session.Secret {
+		AuthenticationConfig.Session.Secret = randomString(10)
+	}
+
+	AuthenticationConfig.Session.ExpireTime = configuration.Get("authentication.session.expireTime").Uint()
 }
 
 func initSchema() {
diff --git a/api/conf/schema.json b/api/conf/schema.json
index bf606b5..087cf4c 100644
--- a/api/conf/schema.json
+++ b/api/conf/schema.json
@@ -1 +1 @@
-{"plugins":{"serverless-post-function":{"type":"object","properties":{"phase":{"type":"string","enum":["rewrite","access","header_filter","body_filter","log","balancer"]},"functions":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["functions"]},"prometheus":{"type":"object","additionalProperties":false},"syslog":{"type":"object","properties":{"port":{"type":"integer"},"flush_limit":{"type":"integer","default":4096,"minimum":1},"name":{"type":"string","default":"sys l [...]
+{"main":{"upstream_hash_header_schema":{"type":"string","pattern":"^[a-zA-Z0-9-_]+$"},"stream_route":{"type":"object","properties":{"plugins":{"type":"object"},"id":{"anyOf":[{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9-_]+$"},{"type":"integer","minimum":1}]},"remote_addr":{"type":"string","anyOf":[{"title":"IPv4","type":"string","pattern":"^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"},{"title":"IPv4/CIDR","type":"string","pattern":"^[0-9]{1,3}.[0-9]{1,3}.[0-9]{ [...]
diff --git a/api/errno/error.go b/api/errno/error.go
deleted file mode 100644
index 0c18dec..0000000
--- a/api/errno/error.go
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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 errno
-
-import (
-	"encoding/json"
-	"fmt"
-)
-
-type Message struct {
-	Code   string
-	Msg    string `json:"message"`
-	Status int    `json:"-"`
-}
-
-var (
-	//AA 01 api-manager-api
-	//BB 00 system
-	SystemSuccess      = Message{"010000", "success", 200}
-	SystemError        = Message{"010001", "system error", 500}
-	BadRequestError    = Message{"010002", "Request format error", 400}
-	NotFoundError      = Message{"010003", "No resources found", 404}
-	InvalidParam       = Message{"010004", "Request parameter error", 400}
-	DBWriteError       = Message{"010005", "Database save failed", 500}
-	DBReadError        = Message{"010006", "Database query failed", 500}
-	DBDeleteError      = Message{"010007", "Database delete failed", 500}
-	RecordNotExist     = Message{"010009", "Record does not exist", 404}
-	InvalidParamDetail = Message{"010010", "Invalid request parameter: %s", 400}
-	AdminApiSaveError  = Message{"010011", "Data save failed", 500}
-	SchemaCheckFailed  = Message{"010012", "%s", 400}
-	ForbiddenError     = Message{"010013", "Request Unauthorized", 401}
-
-	//BB 01 configuration
-	ConfEnvError      = Message{"010101", "Environment variable not found: %s", 500}
-	ConfFilePathError = Message{"010102", "Error loading configuration file: %s", 500}
-
-	// BB 02 route
-	RouteRequestError       = Message{"010201", "Route request parameters are abnormal: %s", 400}
-	ApisixRouteCreateError  = Message{"010202", "Failed to create APISIX route: %s", 500}
-	DBRouteCreateError      = Message{"010203", "Route storage failure: %s", 500}
-	ApisixRouteUpdateError  = Message{"010204", "Update APISIX routing failed: %s", 500}
-	ApisixRouteDeleteError  = Message{"010205", "Failed to delete APISIX route: %s", 500}
-	DBRouteUpdateError      = Message{"010206", "Route update failed: %s", 500}
-	DBRouteDeleteError      = Message{"010207", "Route deletion failed: %s", 500}
-	DBRouteReduplicateError = Message{"010208", "Route name is reduplicate : %s", 400}
-	SetRouteUngroupError    = Message{"010209", "Set route ungroup err", 500}
-	RoutePublishError       = Message{"010209", "Route publish error", 400}
-
-	// 03 plugins
-	ApisixPluginListError   = Message{"010301", "find APISIX plugin list failed: %s", 500}
-	ApisixPluginSchemaError = Message{"010301", "find APISIX plugin schema failed: %s", 500}
-
-	// 04 ssl
-	SslParseError        = Message{"010401", "Certificate resolution failed: %s", 400}
-	ApisixSslCreateError = Message{"010402", "Failed to create APISIX SSL", 500}
-	ApisixSslUpdateError = Message{"010403", "Failed to update APISIX SSL", 500}
-	ApisixSslDeleteError = Message{"010404", "Failed to delete APISIX SSL", 500}
-	SslForSniNotExists   = Message{"010407", "Ssl for sni not exists:%s", 400}
-	DuplicateSslCert     = Message{"010408", "Duplicate ssl cert", 400}
-
-	// 06 upstream
-	UpstreamRequestError       = Message{"010601", "upstream request parameters exception: %s", 400}
-	UpstreamTransError         = Message{"010602", "Abnormal upstream parameter conversion: %s", 400}
-	DBUpstreamError            = Message{"010603", "upstream storage failure: %s", 500}
-	ApisixUpstreamCreateError  = Message{"010604", "apisix upstream create failed: %s", 500}
-	ApisixUpstreamUpdateError  = Message{"010605", "apisix upstream update failed: %s", 500}
-	ApisixUpstreamDeleteError  = Message{"010606", "apisix upstream delete failed: %s", 500}
-	DBUpstreamDeleteError      = Message{"010607", "upstream storage delete failed: %s", 500}
-	DBUpstreamReduplicateError = Message{"010608", "Upstream name is reduplicate : %s", 500}
-
-	// 07 consumer
-	ApisixConsumerCreateError = Message{"010702", "APISIX Consumer create failed", 500}
-	ApisixConsumerUpdateError = Message{"010703", "APISIX Consumer update failed", 500}
-	ApisixConsumerDeleteError = Message{"010704", "APISIX Consumer delete failed", 500}
-	DuplicateUserName         = Message{"010705", "Duplicate consumer username", 400}
-
-	// 08 routeGroup
-	RouteGroupRequestError      = Message{"010801", "RouteGroup request parameters exception: %s", 400}
-	DBRouteGroupError           = Message{"010802", "RouteGroup storage failure: %s", 500}
-	DBRouteGroupDeleteError     = Message{"010803", "RouteGroup storage delete failed: %s", 500}
-	RouteGroupHasRoutesError    = Message{"010804", "Route exist in this route group ", 500}
-	RouteGroupSelectRoutesError = Message{"010805", "RouteGroup select routes failed : %s", 500}
-	DuplicateRouteGroupName     = Message{"010806", "RouteGroup name is duplicate : %s", 500}
-
-	// 99 authentication
-	AuthenticationUserError = Message{"019901", "username or password error", 401}
-)
-
-type ManagerError struct {
-	TraceId string
-	Code    string
-	Status  int
-	Msg     string
-	Data    interface{}
-	Detail  string
-}
-
-// toString
-func (e *ManagerError) Error() string {
-	return e.Msg
-}
-
-func (e *ManagerError) ErrorDetail() string {
-	return fmt.Sprintf("TraceId: %s, Code: %s, Msg: %s, Detail: %s", e.TraceId, e.Code, e.Msg, e.Detail)
-}
-
-func FromMessage(m Message, args ...interface{}) *ManagerError {
-	return &ManagerError{TraceId: "", Code: m.Code, Status: m.Status, Msg: fmt.Sprintf(m.Msg, args...)}
-}
-
-func New(m Message, args ...interface{}) *ManagerError {
-	return &ManagerError{TraceId: "", Code: m.Code, Msg: m.Msg, Status: m.Status, Detail: fmt.Sprintf("%s", args...)}
-}
-
-func (e *ManagerError) Response() map[string]interface{} {
-	return map[string]interface{}{
-		"code":    e.Code,
-		"message": e.Msg,
-	}
-}
-
-func (e *ManagerError) ItemResponse(data interface{}) map[string]interface{} {
-	return map[string]interface{}{
-		"code":    e.Code,
-		"message": e.Msg,
-		"data":    data,
-	}
-}
-
-func (e *ManagerError) ListResponse(count, list interface{}) map[string]interface{} {
-	return map[string]interface{}{
-		"code":    e.Code,
-		"message": e.Msg,
-		"count":   count,
-		"list":    list,
-	}
-}
-
-func Success() []byte {
-	w := FromMessage(SystemSuccess).Response()
-	result, _ := json.Marshal(w)
-	return result
-}
-
-func Succeed() map[string]interface{} {
-	return FromMessage(SystemSuccess).Response()
-}
-
-type HttpError struct {
-	Code int
-	Msg  Message
-}
-
-func (e *HttpError) Error() string {
-	return e.Msg.Msg
-}
diff --git a/api/filter/authentication.go b/api/filter/authentication.go
index ad794af..caebd9a 100644
--- a/api/filter/authentication.go
+++ b/api/filter/authentication.go
@@ -17,12 +17,13 @@
 package filter
 
 import (
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/dgrijalva/jwt-go"
-	"github.com/gin-gonic/gin"
 	"net/http"
 	"strings"
+
+	"github.com/dgrijalva/jwt-go"
+	"github.com/gin-gonic/gin"
+
+	"github.com/apisix/manager-api/conf"
 )
 
 func Authentication() gin.HandlerFunc {
@@ -35,29 +36,34 @@ func Authentication() gin.HandlerFunc {
 				return []byte(conf.AuthenticationConfig.Session.Secret), nil
 			})
 
+			errResp := gin.H{
+				"code":    010013,
+				"message": "Request Unauthorized",
+			}
+
 			if err != nil {
-				c.AbortWithStatusJSON(http.StatusUnauthorized, errno.FromMessage(errno.ForbiddenError).Response())
+				c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
 				return
 			}
 
 			claims, ok := token.Claims.(*jwt.StandardClaims)
 			if !ok {
-				c.AbortWithStatusJSON(http.StatusUnauthorized, errno.FromMessage(errno.ForbiddenError).Response())
+				c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
 				return
 			}
 
 			if err := token.Claims.Valid(); err != nil {
-				c.AbortWithStatusJSON(http.StatusUnauthorized, errno.FromMessage(errno.ForbiddenError).Response())
+				c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
 				return
 			}
 
 			if claims.Subject == "" {
-				c.AbortWithStatusJSON(http.StatusUnauthorized, errno.FromMessage(errno.ForbiddenError).Response())
+				c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
 				return
 			}
 
 			if _, ok := conf.UserList[claims.Subject]; !ok {
-				c.AbortWithStatusJSON(http.StatusUnauthorized, errno.FromMessage(errno.ForbiddenError).Response())
+				c.AbortWithStatusJSON(http.StatusUnauthorized, errResp)
 				return
 			}
 		}
diff --git a/api/filter/logging.go b/api/filter/logging.go
index 6318d52..badf234 100644
--- a/api/filter/logging.go
+++ b/api/filter/logging.go
@@ -21,7 +21,6 @@ import (
 	"io/ioutil"
 	"time"
 
-	"github.com/apisix/manager-api/errno"
 	"github.com/gin-gonic/gin"
 	"github.com/sirupsen/logrus"
 )
@@ -60,9 +59,7 @@ func RequestLogHandler() gin.HandlerFunc {
 		}
 		var errs []string
 		for _, err := range c.Errors {
-			if e, ok := err.Err.(*errno.ManagerError); ok {
-				errs = append(errs, e.Error())
-			}
+			errs = append(errs, err.Error())
 		}
 		logger.WithFields(logrus.Fields{
 			"requestId":  uuid,
diff --git a/api/internal/handler/authentication/authentication.go b/api/internal/handler/authentication/authentication.go
new file mode 100644
index 0000000..5f3a83b
--- /dev/null
+++ b/api/internal/handler/authentication/authentication.go
@@ -0,0 +1,78 @@
+/*
+ * 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 authentication
+
+import (
+	"fmt"
+	"reflect"
+	"time"
+
+	"github.com/dgrijalva/jwt-go"
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/wrapper"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/conf"
+	"github.com/apisix/manager-api/internal/handler"
+)
+
+type Handler struct {
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.POST("/apisix/admin/user/login", wgin.Wraps(h.userLogin,
+		wrapper.InputType(reflect.TypeOf(LoginInput{}))))
+}
+
+type UserSession struct {
+	Token string `json:"token"`
+}
+
+type LoginInput struct {
+	Username string `json:"username" validate:"required"`
+	Password string `json:"password" validate:"required"`
+}
+
+func (h *Handler) userLogin(c droplet.Context) (interface{}, error) {
+	input := c.Input().(*LoginInput)
+	username := input.Username
+	password := input.Password
+
+	user := conf.UserList[username]
+	if username != user.Username || password != user.Password {
+		return nil, fmt.Errorf("username or password error")
+	}
+
+	// create JWT for session
+	claims := jwt.StandardClaims{
+		Subject:   username,
+		IssuedAt:  time.Now().Unix(),
+		ExpiresAt: time.Now().Add(time.Second * time.Duration(conf.AuthenticationConfig.Session.ExpireTime)).Unix(),
+	}
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+	signedToken, _ := token.SignedString([]byte(conf.AuthenticationConfig.Session.Secret))
+
+	// output token
+	return &UserSession{
+		Token: signedToken,
+	}, nil
+}
diff --git a/api/internal/handler/authentication/authentication_test.go b/api/internal/handler/authentication/authentication_test.go
new file mode 100644
index 0000000..01241a9
--- /dev/null
+++ b/api/internal/handler/authentication/authentication_test.go
@@ -0,0 +1,67 @@
+/*
+ * 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 authentication
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/shiningrush/droplet"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAuthentication(t *testing.T) {
+	// init
+	handler := &Handler{}
+	assert.NotNil(t, handler)
+
+	//login
+	input := &LoginInput{}
+	ctx := droplet.NewContext()
+	reqBody := `{
+	  "username": "admin",
+	  "password": "admin"
+  }`
+	json.Unmarshal([]byte(reqBody), input)
+	ctx.SetInput(input)
+	_, err := handler.userLogin(ctx)
+	assert.Nil(t, err)
+
+	//username error
+	input2 := &LoginInput{}
+	reqBody = `{
+	  "username": "sdfasdf",
+	  "password": "admin"
+  }`
+	json.Unmarshal([]byte(reqBody), input2)
+	ctx.SetInput(input2)
+	_, err = handler.userLogin(ctx)
+	assert.EqualError(t, err, "username or password error")
+
+	//password error
+	input3 := &LoginInput{}
+	reqBody = `{
+	  "username": "admin",
+	  "password": "admin9384938"
+  }`
+	json.Unmarshal([]byte(reqBody), input3)
+	ctx.SetInput(input3)
+	_, err = handler.userLogin(ctx)
+	assert.EqualError(t, err, "username or password error")
+
+}
diff --git a/api/internal/handler/handler.go b/api/internal/handler/handler.go
index 2736700..f1d653d 100644
--- a/api/internal/handler/handler.go
+++ b/api/internal/handler/handler.go
@@ -16,7 +16,9 @@
  */
 package handler
 
-import "github.com/gin-gonic/gin"
+import (
+	"github.com/gin-gonic/gin"
+)
 
 type RegisterFactory func() (RouteRegister, error)
 
diff --git a/api/route/healthz.go b/api/internal/handler/healthz/healthz.go
similarity index 65%
rename from api/route/healthz.go
rename to api/internal/handler/healthz/healthz.go
index 243ba5f..c35c860 100644
--- a/api/route/healthz.go
+++ b/api/internal/handler/healthz/healthz.go
@@ -14,25 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package route
+package healthz
 
 import (
-	"net/http"
-
-	"github.com/apisix/manager-api/log"
 	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/internal/handler"
 )
 
-var logger = log.GetLogger()
+type Handler struct {
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{}, nil
+}
 
-func healthzHandler() gin.HandlerFunc {
-	return func(c *gin.Context) {
-		c.Copy()
-		c.String(http.StatusOK, "pong")
-	}
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.GET("/ping", wgin.Wraps(h.healthZHandler))
 }
 
-func AppendHealthCheck(r *gin.Engine) *gin.Engine {
-	r.GET("/ping", healthzHandler())
-	return r
+func (h *Handler) healthZHandler(c droplet.Context) (interface{}, error) {
+	return "pong", nil
 }
diff --git a/api/internal/handler/plugin/plugin.go b/api/internal/handler/plugin/plugin.go
new file mode 100644
index 0000000..354c562
--- /dev/null
+++ b/api/internal/handler/plugin/plugin.go
@@ -0,0 +1,65 @@
+/*
+ * 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 plugin
+
+import (
+	"reflect"
+
+	"github.com/gin-gonic/gin"
+	"github.com/shiningrush/droplet"
+	"github.com/shiningrush/droplet/wrapper"
+	wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+	"github.com/apisix/manager-api/conf"
+	"github.com/apisix/manager-api/internal/handler"
+)
+
+type Handler struct {
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+	return &Handler{}, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+	r.GET("/apisix/admin/plugins", wgin.Wraps(h.Plugins))
+	r.GET("/apisix/admin/schema/plugins/:name", wgin.Wraps(h.Schema,
+		wrapper.InputType(reflect.TypeOf(GetInput{}))))
+}
+
+type GetInput struct {
+	Name string `auto_read:"name,path" validate:"required"`
+}
+
+func (h *Handler) Schema(c droplet.Context) (interface{}, error) {
+	input := c.Input().(*GetInput)
+	ret := conf.Schema.Get("plugins." + input.Name).Value()
+	return ret, nil
+}
+
+func (h *Handler) Plugins(c droplet.Context) (interface{}, error) {
+	list := conf.Schema.Get("plugins").Map()
+
+	var ret []string
+	for pluginName, _ := range list {
+		if pluginName != "serverless-post-function" && pluginName != "serverless-pre-function" {
+			ret = append(ret, pluginName)
+		}
+	}
+
+	return ret, nil
+}
diff --git a/api/route/base_test.go b/api/internal/handler/plugin/plugin_test.go
similarity index 52%
rename from api/route/base_test.go
rename to api/internal/handler/plugin/plugin_test.go
index 838f4b7..d962a6a 100644
--- a/api/route/base_test.go
+++ b/api/internal/handler/plugin/plugin_test.go
@@ -14,43 +14,45 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package route
 
-import (
-	"strings"
-
-	"github.com/api7/apitest"
-	dlog "github.com/shiningrush/droplet/log"
-	"github.com/spf13/viper"
+package plugin
 
-	"github.com/apisix/manager-api/internal/core/storage"
-	"github.com/apisix/manager-api/internal/core/store"
-	"github.com/apisix/manager-api/log"
-)
-
-var testHandler *apitest.APITest
+import (
+	"encoding/json"
+	"testing"
 
-var (
-	uriPrefix = "/apisix/admin"
+	"github.com/shiningrush/droplet"
+	"github.com/stretchr/testify/assert"
 )
 
-func init() {
-	//init etcd
-	viper.SetEnvPrefix("APIX")
-	viper.AutomaticEnv()
-	dlog.DefLogger = log.DefLogger{}
-
-	if err := storage.InitETCDClient(strings.Split(viper.GetString("etcd_endpoints"), ",")); err != nil {
-		panic(err)
-	}
-
-	if err := store.InitStores(); err != nil {
-		panic(err)
-	}
-
-	r := SetUpRouter()
-
-	testHandler = apitest.
-		New().
-		Handler(r)
+func TestPlugin(t *testing.T) {
+	// init
+	handler := &Handler{}
+	assert.NotNil(t, handler)
+
+	//plugin list
+	ctx := droplet.NewContext()
+	list, err := handler.Plugins(ctx)
+	assert.Nil(t, err)
+	assert.Contains(t, list.([]string), "limit-count")
+
+	//schema
+	input := &GetInput{}
+	reqBody := `{
+	  "name": "limit-count"
+  }`
+	json.Unmarshal([]byte(reqBody), input)
+	ctx.SetInput(input)
+	val, _ := handler.Schema(ctx)
+	assert.NotNil(t, val)
+
+	//not exists
+	input2 := &GetInput{}
+	reqBody = `{
+	  "name": "not-exists"
+  }`
+	json.Unmarshal([]byte(reqBody), input2)
+	ctx.SetInput(input2)
+	val, _ = handler.Schema(ctx)
+	assert.Nil(t, val)
 }
diff --git a/api/route/base.go b/api/internal/route.go
similarity index 88%
rename from api/route/base.go
rename to api/internal/route.go
index 979e750..9814620 100644
--- a/api/route/base.go
+++ b/api/internal/route.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package route
+package internal
 
 import (
 	"github.com/gin-contrib/pprof"
@@ -25,7 +25,10 @@ import (
 	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/filter"
 	"github.com/apisix/manager-api/internal/handler"
+	"github.com/apisix/manager-api/internal/handler/authentication"
 	"github.com/apisix/manager-api/internal/handler/consumer"
+	"github.com/apisix/manager-api/internal/handler/healthz"
+	"github.com/apisix/manager-api/internal/handler/plugin"
 	"github.com/apisix/manager-api/internal/handler/route"
 	"github.com/apisix/manager-api/internal/handler/service"
 	"github.com/apisix/manager-api/internal/handler/ssl"
@@ -43,22 +46,17 @@ func SetUpRouter() *gin.Engine {
 	r.Use(sessions.Sessions("session", store))
 	r.Use(filter.CORS(), filter.Authentication(), filter.RequestId(), filter.RecoverHandler())
 
-	AppendHealthCheck(r)
-	AppendAuthentication(r)
-	//AppendRoute(r)
-	//AppendSsl(r)
-	AppendPlugin(r)
-	//AppendUpstream(r)
-	//AppendConsumer(r)
-	AppendRouteGroup(r)
-
 	factories := []handler.RegisterFactory{
 		route.NewHandler,
 		ssl.NewHandler,
 		consumer.NewHandler,
 		upstream.NewHandler,
 		service.NewHandler,
+		plugin.NewHandler,
+		healthz.NewHandler,
+		authentication.NewHandler,
 	}
+
 	for i := range factories {
 		h, err := factories[i]()
 		if err != nil {
diff --git a/api/main.go b/api/main.go
index 937243e..74b3a12 100644
--- a/api/main.go
+++ b/api/main.go
@@ -18,19 +18,19 @@ package main
 
 import (
 	"fmt"
-	"github.com/spf13/viper"
 	"net/http"
 	"strings"
 	"time"
 
 	dlog "github.com/shiningrush/droplet/log"
+	"github.com/spf13/viper"
 
 	"github.com/apisix/manager-api/conf"
+	"github.com/apisix/manager-api/internal"
 	"github.com/apisix/manager-api/internal/core/storage"
 	"github.com/apisix/manager-api/internal/core/store"
 	"github.com/apisix/manager-api/internal/utils"
 	"github.com/apisix/manager-api/log"
-	"github.com/apisix/manager-api/route"
 )
 
 var logger = log.GetLogger()
@@ -47,10 +47,8 @@ func main() {
 		panic(err)
 	}
 
-	// init
-	//conf.InitializeMysql()
 	// routes
-	r := route.SetUpRouter()
+	r := internal.SetUpRouter()
 	addr := fmt.Sprintf(":%d", conf.ServerPort)
 	s := &http.Server{
 		Addr:         addr,
diff --git a/api/route/authentication.go b/api/route/authentication.go
deleted file mode 100644
index 9284dc1..0000000
--- a/api/route/authentication.go
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 route
-
-import (
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	jwt "github.com/dgrijalva/jwt-go"
-	"github.com/gin-gonic/gin"
-	"net/http"
-	"time"
-)
-
-type UserSession struct {
-	Token string `json:"token"`
-}
-
-func AppendAuthentication(r *gin.Engine) *gin.Engine {
-	r.POST("/apisix/admin/user/login", userLogin)
-	return r
-}
-
-func userLogin(c *gin.Context) {
-	username := c.PostForm("username")
-	password := c.PostForm("password")
-
-	if username == "" {
-		c.AbortWithStatusJSON(http.StatusBadRequest, errno.FromMessage(errno.InvalidParamDetail, "username is needed").Response())
-		return
-	}
-	if password == "" {
-		c.AbortWithStatusJSON(http.StatusBadRequest, errno.FromMessage(errno.InvalidParamDetail, "password is needed").Response())
-		return
-	}
-
-	user := conf.UserList[username]
-	if username != user.Username || password != user.Password {
-		c.AbortWithStatusJSON(http.StatusUnauthorized, errno.FromMessage(errno.AuthenticationUserError).Response())
-	} else {
-		// create JWT for session
-		claims := jwt.StandardClaims{
-			Subject:   username,
-			IssuedAt:  time.Now().Unix(),
-			ExpiresAt: time.Now().Add(time.Second * time.Duration(conf.AuthenticationConfig.Session.ExpireTime)).Unix(),
-		}
-		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
-		signedToken, _ := token.SignedString([]byte(conf.AuthenticationConfig.Session.Secret))
-
-		// output token
-		c.AbortWithStatusJSON(http.StatusOK, errno.FromMessage(errno.SystemSuccess).ItemResponse(&UserSession{
-			Token: signedToken,
-		}))
-	}
-}
diff --git a/api/route/authentication_test.go b/api/route/authentication_test.go
deleted file mode 100644
index 952a689..0000000
--- a/api/route/authentication_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 route
-
-import (
-	"bytes"
-	"net/http"
-	"strings"
-	"testing"
-)
-
-var token string
-
-func TestUserLogin(t *testing.T) {
-	// password error
-	testHandler.
-		Post("/apisix/admin/user/login").
-		Header("Content-Type", "application/x-www-form-urlencoded").
-		Body("username=admin&password=admin1").
-		Expect(t).
-		Status(http.StatusUnauthorized).
-		End()
-
-	// login success
-	sessionResponse := testHandler.
-		Post("/apisix/admin/user/login").
-		Header("Content-Type", "application/x-www-form-urlencoded").
-		Body("username=admin&password=admin").
-		Expect(t).
-		Status(http.StatusOK).
-		End().Response.Body
-
-	buf := new(bytes.Buffer)
-	buf.ReadFrom(sessionResponse)
-	data := buf.String()
-	tokenArr := strings.Split(data, "\"token\":\"")
-	token = strings.Split(tokenArr[1], "\"}")[0]
-}
diff --git a/api/route/consumer.go b/api/route/consumer.go
deleted file mode 100644
index 3f0bfa1..0000000
--- a/api/route/consumer.go
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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 route
-
-import (
-	"net/http"
-	"strconv"
-
-	"github.com/gin-gonic/gin"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/service"
-	uuid "github.com/satori/go.uuid"
-)
-
-func AppendConsumer(r *gin.Engine) *gin.Engine {
-
-	r.GET("/apisix/admin/consumers", consumerList)
-	r.POST("/apisix/admin/consumers", consumerCreate)
-	r.GET("/apisix/admin/consumers/:id", consumerItem)
-	r.PUT("/apisix/admin/consumers/:id", consumerUpdate)
-	r.DELETE("/apisix/admin/consumers/:id", consumerDelete)
-
-	return r
-}
-
-func handleServiceError(c *gin.Context, requestId interface{}, err error) {
-	if httpError, ok := err.(*errno.HttpError); ok {
-		logger.WithField(conf.RequestId, requestId).Error(err)
-		c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-		return
-	}
-
-	e := err.(*errno.ManagerError)
-	status := http.StatusInternalServerError
-	if e.Status > 0 {
-		status = e.Status
-	}
-	logger.WithField(conf.RequestId, requestId).Error(e.ErrorDetail())
-	c.AbortWithStatusJSON(status, e.Response())
-}
-
-func consumerList(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
-	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
-
-	search := c.DefaultQuery("search", "")
-
-	count, list, err := service.ConsumerList(page, size, search)
-
-	if err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	resp := errno.FromMessage(errno.SystemSuccess).ListResponse(count, list)
-
-	c.JSON(http.StatusOK, resp)
-}
-
-func consumerItem(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	id := c.Param("id")
-
-	consumer, err := service.ConsumerItem(id)
-
-	if err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.FromMessage(errno.SystemSuccess).ItemResponse(consumer))
-}
-
-func consumerCreate(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-
-	u4 := uuid.NewV4()
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	if err := service.ConsumerCreate(param, u4.String()); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
-
-func consumerUpdate(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-
-	id := c.Param("id")
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	if err := service.ConsumerUpdate(param, id); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
-
-func consumerDelete(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	id := c.Param("id")
-
-	if err := service.ConsumerDelete(id); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
diff --git a/api/route/consumer_test.go b/api/route/consumer_test.go
deleted file mode 100644
index 3793804..0000000
--- a/api/route/consumer_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 route
-
-import (
-	"net/http"
-	"testing"
-)
-
-func TestConsumer(t *testing.T) {
-	// create ok
-	username1 := "e2e_test_consumer1"
-	testHandler.
-		Post(uriPrefix+"/consumers").
-		Header("Authorization", token).
-		JSON(`{
-			"username": "` + username1 + `",
-			"plugins": {
-				"limit-count": {
-					"count": 2,
-					"time_window": 60,
-					"rejected_code": 503,
-					"key": "remote_addr"
-				},
-				"basic-auth": {
-					"username": "foo",
-					"password": "bar"
-				}
-			},
-			"desc": "test description"
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//update ok
-	testHandler.
-		Put(uriPrefix + "/consumers/" + username1).
-		JSON(`{
-			"username": "e2e_test_consumer1",
-			"plugins": {
-				"limit-count": {
-					"count": 2,
-					"time_window": 60,
-					"rejected_code": 503,
-					"key": "remote_addr"
-				},
-				"basic-auth": {
-					"username": "foo",
-					"password": "bar"
-				}
-			},
-			"desc": "test desc"
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//list
-	testHandler.
-		Get(uriPrefix + "/consumers").
-		Headers(map[string]string{"Authorization": token}).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//delete
-	testHandler.
-		Delete(uriPrefix + "/consumers/" + username1).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-}
diff --git a/api/route/plugin.go b/api/route/plugin.go
deleted file mode 100644
index dad545d..0000000
--- a/api/route/plugin.go
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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 route
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/service"
-	"github.com/gin-gonic/gin"
-)
-
-func AppendPlugin(r *gin.Engine) *gin.Engine {
-	r.GET("/apisix/admin/plugins", listPlugin)
-	r.GET("/apisix/admin/schema/plugins/:name", findSchema)
-	return r
-}
-
-func findSchema(c *gin.Context) {
-	name := c.Param("name")
-	request := &service.ApisixPluginRequest{Name: name}
-	if result, err := request.Schema(); err != nil {
-		e := errno.FromMessage(errno.ApisixPluginSchemaError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	} else {
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
-
-func listPlugin(c *gin.Context) {
-	request := &service.ApisixPluginRequest{}
-	if result, err := request.List(); err != nil {
-		e := errno.FromMessage(errno.ApisixPluginListError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	} else {
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
diff --git a/api/route/route.go b/api/route/route.go
deleted file mode 100644
index 48f89fd..0000000
--- a/api/route/route.go
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * 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 route
-
-import (
-	"encoding/json"
-	"net/http"
-	"strconv"
-	"strings"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/service"
-	"github.com/gin-gonic/gin"
-	uuid "github.com/satori/go.uuid"
-)
-
-func AppendRoute(r *gin.Engine) *gin.Engine {
-	r.POST("/apisix/admin/routes", createRoute)
-	r.GET("/apisix/admin/routes/:rid", findRoute)
-	r.GET("/apisix/admin/routes", listRoute)
-	r.PUT("/apisix/admin/routes/:rid", updateRoute)
-	r.PUT("/apisix/admin/routes/:rid/publish", publishRoute)
-	r.DELETE("/apisix/admin/routes/:rid", deleteRoute)
-	r.GET("/apisix/admin/notexist/routes", isRouteExist)
-	r.PUT("/apisix/admin/routes/:rid/offline", offlineRoute)
-	return r
-}
-
-func publishRoute(c *gin.Context) {
-	rid := c.Param("rid")
-	r := &service.Route{}
-	tx := conf.DB().Begin()
-	if err := tx.Model(&service.Route{}).Where("id = ?", rid).Update("status", true).Find(&r).Error; err != nil {
-		tx.Rollback()
-		e := errno.FromMessage(errno.RoutePublishError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		routeRequest := &service.RouteRequest{}
-		if err := json.Unmarshal([]byte(r.Content), routeRequest); err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.RoutePublishError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			routeRequest.Status = true
-		}
-		if content, err := json.Marshal(routeRequest); err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.RoutePublishError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			r.Content = string(content)
-		}
-		arr := service.ToApisixRequest(routeRequest)
-		var resp *service.ApisixRouteResponse
-		if resp, err = arr.Create(rid); err != nil {
-			tx.Rollback()
-			if httpError, ok := err.(*errno.HttpError); ok {
-				c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-				return
-			} else {
-				e := errno.FromMessage(errno.ApisixRouteCreateError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		} else {
-			resp.Node.Value.Name = r.Name
-			resp.Node.Value.Status = r.Status
-			if respStr, err := json.Marshal(resp); err != nil {
-				e := errno.FromMessage(errno.RoutePublishError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			} else {
-				r.ContentAdminApi = string(respStr)
-			}
-		}
-		if err := tx.Commit().Error; err == nil {
-			// update content_admin_api
-			if err := conf.DB().Model(&service.Route{}).Update(r).Error; err != nil {
-				e := errno.FromMessage(errno.DBRouteUpdateError, err.Error())
-				logger.Error(e.Msg)
-			}
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func offlineRoute(c *gin.Context) {
-	rid := c.Param("rid")
-	db := conf.DB()
-	tx := db.Begin()
-	route := &service.Route{}
-	if err := tx.Model(&service.Route{}).Where("id = ?", rid).Update(map[string]interface{}{"status": 0, "content_admin_api": ""}).First(&route).Error; err != nil {
-		tx.Rollback()
-		e := errno.FromMessage(errno.RoutePublishError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		routeRequest := &service.RouteRequest{}
-		if err := json.Unmarshal([]byte(route.Content), routeRequest); err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.RoutePublishError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			routeRequest.Status = false
-		}
-		if content, err := json.Marshal(routeRequest); err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.RoutePublishError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			route.Content = string(content)
-		}
-		request := &service.ApisixRouteRequest{}
-		if _, err := request.Delete(rid); err != nil {
-			tx.Rollback()
-			if httpError, ok := err.(*errno.HttpError); ok {
-				c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-				return
-			} else {
-				e := errno.FromMessage(errno.ApisixRouteDeleteError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		}
-		if err := tx.Model(&service.Route{}).Update(route).Error; err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.DBRouteUpdateError, err.Error())
-			logger.Error(e.Msg)
-			return
-		}
-	}
-	if err := tx.Commit().Error; err != nil {
-		e := errno.FromMessage(errno.ApisixRouteDeleteError, err.Error())
-		logger.Error(e.Msg)
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func isRouteExist(c *gin.Context) {
-	if name, exist := c.GetQuery("name"); exist {
-		db := conf.DB()
-		db = db.Table("routes")
-		exclude, exist := c.GetQuery("exclude")
-		if exist {
-			db = db.Where("name=? and id<>?", name, exclude)
-		} else {
-			db = db.Where("name=?", name)
-		}
-		var count int
-		err := db.Count(&count).Error
-		if err != nil {
-			e := errno.FromMessage(errno.RouteRequestError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			if count == 0 {
-				c.Data(http.StatusOK, service.ContentType, errno.Success())
-				return
-			} else {
-				e := errno.FromMessage(errno.DBRouteReduplicateError, name)
-				c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-				return
-			}
-		}
-	} else {
-		e := errno.FromMessage(errno.RouteRequestError, "name is needed")
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-}
-
-func listRoute(c *gin.Context) {
-	db := conf.DB()
-	size, _ := strconv.Atoi(c.Query("size"))
-	page, _ := strconv.Atoi(c.Query("page"))
-	if size == 0 {
-		size = 10
-	}
-	db = db.Table("routes")
-	isSearch := true
-	if name, exist := c.GetQuery("name"); exist {
-		db = db.Where("name like ? ", "%"+name+"%")
-		isSearch = false
-	}
-	if description, exist := c.GetQuery("description"); exist {
-		db = db.Where("description like ? ", "%"+description+"%")
-		isSearch = false
-	}
-	if host, exist := c.GetQuery("host"); exist {
-		db = db.Where("hosts like ? ", "%"+host+"%")
-		isSearch = false
-	}
-	if uri, exist := c.GetQuery("uri"); exist {
-		db = db.Where("uris like ? ", "%"+uri+"%")
-		isSearch = false
-	}
-	if ip, exist := c.GetQuery("ip"); exist {
-		db = db.Where("upstream_nodes like ? ", "%"+ip+"%")
-		isSearch = false
-	}
-	if rgid, exist := c.GetQuery("route_group_id"); exist {
-		db = db.Where("route_group_id = ?", rgid)
-		isSearch = false
-	}
-	if rgName, exist := c.GetQuery("route_group_name"); exist {
-		db = db.Where("route_group_name like ?", "%"+rgName+"%")
-		isSearch = false
-	}
-	// search
-	if isSearch {
-		if search, exist := c.GetQuery("search"); exist {
-			s := "%" + search + "%"
-			db = db.Where("name like ? or description like ? or hosts like ? or uris like ? or upstream_nodes like ? or route_group_id = ? or route_group_name like ?", s, s, s, s, s, search, s)
-		}
-	}
-	// mysql
-	routeList := []service.Route{}
-	var count int
-	if err := db.Order("priority, update_time desc").Table("routes").Offset((page - 1) * size).Limit(size).Find(&routeList).Error; err != nil {
-		e := errno.FromMessage(errno.RouteRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	} else {
-		responseList := make([]service.RouteResponse, 0)
-		for _, r := range routeList {
-			response := &service.RouteResponse{}
-			response.Parse(&r)
-			responseList = append(responseList, *response)
-		}
-		if err := db.Count(&count).Error; err != nil {
-			e := errno.FromMessage(errno.RouteRequestError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		}
-		result := &service.ListResponse{Count: count, Data: responseList}
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
-
-func deleteRoute(c *gin.Context) {
-	rid := c.Param("rid")
-	db := conf.DB()
-	tx := db.Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-	// delete from mysql
-	rd := &service.Route{}
-	rd.ID = uuid.FromStringOrNil(rid)
-	if err := db.Table("routes").Where("id=?", rid).First(&rd).Error; err != nil {
-		e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	}
-	if err := conf.DB().Delete(rd).Error; err != nil {
-		tx.Rollback()
-		e := errno.FromMessage(errno.DBRouteDeleteError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else if rd.Status {
-		request := &service.ApisixRouteRequest{}
-		if _, err := request.Delete(rid); err != nil {
-			tx.Rollback()
-			if httpError, ok := err.(*errno.HttpError); ok {
-				c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-				return
-			} else {
-				e := errno.FromMessage(errno.ApisixRouteDeleteError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		}
-	}
-	if err := tx.Commit().Error; err != nil {
-		e := errno.FromMessage(errno.ApisixRouteDeleteError, err.Error())
-		logger.Error(e.Msg)
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-func updateRoute(c *gin.Context) {
-	rid := c.Param("rid")
-	param, exist := c.Get("requestBody")
-	if !exist || len(param.([]byte)) < 1 {
-		e := errno.FromMessage(errno.RouteRequestError, "route create with no post data")
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	routeRequest := &service.RouteRequest{}
-	if err := routeRequest.Parse(param); err != nil {
-		e := errno.FromMessage(errno.RouteRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	routeGroup := &service.RouteGroupDao{}
-	isCreateGroup := false
-	isUngroup := false
-	if len(strings.Trim(routeRequest.RouteGroupId, "")) == 0 {
-		if len(strings.Trim(routeRequest.RouteGroupName, "")) > 0 {
-			isCreateGroup = true
-			routeGroup.ID = uuid.NewV4()
-			// create route group
-			routeGroup.Name = routeRequest.RouteGroupName
-			routeRequest.RouteGroupId = routeGroup.ID.String()
-		} else {
-			isUngroup = true
-		}
-	}
-	logger.Info(routeRequest.Plugins)
-	db := conf.DB()
-	arr := service.ToApisixRequest(routeRequest)
-	var resp *service.ApisixRouteResponse
-	var r *service.Route
-	if rd, err := service.ToRoute(routeRequest, arr, uuid.FromStringOrNil(rid), nil); err != nil {
-		c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response())
-		return
-	} else {
-		r = rd
-		tx := db.Begin()
-		defer func() {
-			if r := recover(); r != nil {
-				tx.Rollback()
-			}
-		}()
-		logger.Info(rd)
-		if isCreateGroup {
-			if err := tx.Model(&service.RouteGroupDao{}).Create(routeGroup).Error; err != nil {
-				tx.Rollback()
-				e := errno.FromMessage(errno.DuplicateRouteGroupName, routeGroup.Name)
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		}
-		if err := tx.Model(&service.Route{}).Update(rd).Error; err != nil {
-			// rollback
-			tx.Rollback()
-			e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else if rd.Status {
-			if resp, err = arr.Update(rid); err != nil {
-				tx.Rollback()
-				if httpError, ok := err.(*errno.HttpError); ok {
-					c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-					return
-				} else {
-					e := errno.FromMessage(errno.ApisixRouteCreateError, err.Error())
-					logger.Error(e.Msg)
-					c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-					return
-				}
-			}
-		}
-		if isUngroup {
-			if err := tx.Model(&service.Route{}).Where("id = ?", rid).Update(map[string]interface{}{"route_group_id": "", "route_group_name": ""}).Error; err != nil {
-				tx.Rollback()
-				e := errno.FromMessage(errno.SetRouteUngroupError)
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		}
-		if err := tx.Commit().Error; err == nil && r.Status {
-			// update content_admin_api
-			if rd, err := service.ToRoute(routeRequest, arr, uuid.FromStringOrNil(rid), resp); err != nil {
-				e := errno.FromMessage(errno.DBRouteUpdateError, err.Error())
-				logger.Error(e.Msg)
-			} else {
-				if err := conf.DB().Model(&service.Route{}).Update(rd).Error; err != nil {
-					e := errno.FromMessage(errno.DBRouteUpdateError, err.Error())
-					logger.Error(e.Msg)
-				}
-			}
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func findRoute(c *gin.Context) {
-	rid := c.Param("rid")
-	route := &service.Route{}
-	var count int
-	if err := conf.DB().Table("routes").Where("id=?", rid).Count(&count).First(&route).Error; err != nil {
-		e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		if count < 1 {
-			e := errno.FromMessage(errno.RouteRequestError, " route ID: "+rid+" not exist")
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(e.Status, e.Response())
-			return
-		}
-	}
-	if !route.Status {
-		routeRequest := &service.RouteRequest{}
-		if err := json.Unmarshal([]byte(route.Content), &routeRequest); err != nil {
-			e := errno.FromMessage(errno.RouteRequestError, " route ID: "+rid+" not exist")
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(e.Status, e.Response())
-			return
-		} else {
-			routeRequest.Name = route.Name
-			resp, _ := json.Marshal(routeRequest)
-			c.Data(http.StatusOK, service.ContentType, resp)
-		}
-	} else {
-		// find from apisix
-		request := &service.ApisixRouteRequest{}
-		if response, err := request.FindById(rid); err != nil {
-			e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid)
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-			return
-		} else {
-			// transfer response to dashboard struct
-			if result, err := response.Parse(); err != nil {
-				e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid)
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-				return
-			} else {
-				// need to find name from mysql temporary
-				result.Name = route.Name
-				var script map[string]interface{}
-				if err = json.Unmarshal([]byte(route.Script), &script); err != nil {
-					script = map[string]interface{}{}
-				}
-				result.Script = script
-
-				result.RouteGroupId = route.RouteGroupId
-				result.RouteGroupName = route.RouteGroupName
-				result.Status = true
-				resp, _ := json.Marshal(result)
-				c.Data(http.StatusOK, service.ContentType, resp)
-			}
-		}
-	}
-}
-
-func createRoute(c *gin.Context) {
-	u4 := uuid.NewV4()
-	rid := u4.String()
-	param, exist := c.Get("requestBody")
-	if !exist || len(param.([]byte)) < 1 {
-		e := errno.FromMessage(errno.RouteRequestError, "route create with no post data")
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	routeRequest := &service.RouteRequest{}
-	if err := routeRequest.Parse(param); err != nil {
-		e := errno.FromMessage(errno.RouteRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	routeGroup := &service.RouteGroupDao{}
-	isCreateGroup := false
-	if len(strings.Trim(routeRequest.RouteGroupId, "")) == 0 {
-		// create route group
-		if len(strings.Trim(routeRequest.RouteGroupName, "")) > 0 {
-			isCreateGroup = true
-			routeGroup.ID = uuid.NewV4()
-			routeGroup.Name = routeRequest.RouteGroupName
-			routeRequest.RouteGroupId = routeGroup.ID.String()
-		}
-	}
-	logger.Info(routeRequest.Plugins)
-	db := conf.DB()
-	arr := service.ToApisixRequest(routeRequest)
-	var resp *service.ApisixRouteResponse
-	var r *service.Route
-	if rd, err := service.ToRoute(routeRequest, arr, u4, nil); err != nil {
-		c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response())
-		return
-	} else {
-		r = rd
-		tx := db.Begin()
-		defer func() {
-			if r := recover(); r != nil {
-				tx.Rollback()
-			}
-		}()
-		logger.Info(rd)
-		if isCreateGroup {
-			if err := tx.Model(&service.RouteGroupDao{}).Create(routeGroup).Error; err != nil {
-				tx.Rollback()
-				e := errno.FromMessage(errno.DuplicateRouteGroupName, routeGroup.Name)
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		}
-		if err := tx.Model(&service.Route{}).Create(rd).Error; err != nil {
-			// rollback
-			tx.Rollback()
-			e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else if rd.Status {
-			if resp, err = arr.Create(rid); err != nil {
-				tx.Rollback()
-				if httpError, ok := err.(*errno.HttpError); ok {
-					c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-					return
-				} else {
-					e := errno.FromMessage(errno.ApisixRouteCreateError, err.Error())
-					logger.Error(e.Msg)
-					c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-					return
-				}
-			}
-		}
-		if err := tx.Commit().Error; err == nil && r.Status {
-			// update content_admin_api
-			if rd, err := service.ToRoute(routeRequest, arr, u4, resp); err != nil {
-				e := errno.FromMessage(errno.DBRouteUpdateError, err.Error())
-				logger.Error(e.Msg)
-			} else {
-				if err := conf.DB().Model(&service.Route{}).Update(rd).Error; err != nil {
-					e := errno.FromMessage(errno.DBRouteUpdateError, err.Error())
-					logger.Error(e.Msg)
-				}
-			}
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
diff --git a/api/route/route_group.go b/api/route/route_group.go
deleted file mode 100644
index 7be8538..0000000
--- a/api/route/route_group.go
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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 route
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"strconv"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/service"
-	"github.com/gin-gonic/gin"
-	uuid "github.com/satori/go.uuid"
-)
-
-func AppendRouteGroup(r *gin.Engine) *gin.Engine {
-	r.POST("/apisix/admin/routegroups", createRouteGroup)
-	r.GET("/apisix/admin/routegroups/:gid", findRouteGroup)
-	r.GET("/apisix/admin/routegroups", listRouteGroup)
-	r.GET("/apisix/admin/names/routegroups", listRouteGroupName)
-	r.PUT("/apisix/admin/routegroups/:gid", updateRouteGroup)
-	r.DELETE("/apisix/admin/routegroups/:gid", deleteRouteGroup)
-	r.GET("/apisix/admin/notexist/routegroups", isRouteGroupExist)
-	return r
-}
-
-func isRouteGroupExist(c *gin.Context) {
-	if name, exist := c.GetQuery("name"); exist {
-		db := conf.DB()
-		db = db.Table("route_group")
-		exclude, exist := c.GetQuery("exclude")
-		if exist {
-			db = db.Where("name=? and id<>?", name, exclude)
-		} else {
-			db = db.Where("name=?", name)
-		}
-		var count int
-		if err := db.Count(&count).Error; err != nil {
-			e := errno.FromMessage(errno.RouteGroupRequestError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			if count == 0 {
-				c.Data(http.StatusOK, service.ContentType, errno.Success())
-				return
-			} else {
-				e := errno.FromMessage(errno.DuplicateRouteGroupName, name)
-				c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-				return
-			}
-		}
-	} else {
-		e := errno.FromMessage(errno.RouteGroupRequestError, "name is needed")
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-}
-
-func createRouteGroup(c *gin.Context) {
-	u4 := uuid.NewV4()
-	gid := u4.String()
-	// todo 参数校验
-	param, exist := c.Get("requestBody")
-	if !exist || len(param.([]byte)) < 1 {
-		e := errno.FromMessage(errno.RouteRequestError, "route_group create with no post data")
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	// trans params
-	rr := &service.RouteGroupRequest{}
-	if err := rr.Parse(param); err != nil {
-		e := errno.FromMessage(errno.RouteGroupRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	rr.Id = gid
-	fmt.Println(rr)
-	// mysql
-	if rd, err := service.Trans2RouteGroupDao(rr); err != nil {
-		c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response())
-		return
-	} else {
-		if err := rd.CreateRouteGroup(); err != nil {
-			e := errno.FromMessage(errno.DBRouteGroupError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func findRouteGroup(c *gin.Context) {
-	gid := c.Param("gid")
-	routeGroup := &service.RouteGroupDao{}
-	if err, count := routeGroup.FindRouteGroup(gid); err != nil {
-		e := errno.FromMessage(errno.RouteGroupRequestError, err.Error()+"route_group ID:"+gid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	} else {
-		if count < 1 {
-			e := errno.FromMessage(errno.RouteRequestError, " route_group ID: "+gid+" not exist")
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(e.Status, e.Response())
-			return
-		}
-	}
-	resp, _ := json.Marshal(routeGroup)
-	c.Data(http.StatusOK, service.ContentType, resp)
-}
-
-func listRouteGroup(c *gin.Context) {
-	size, _ := strconv.Atoi(c.Query("size"))
-	page, _ := strconv.Atoi(c.Query("page"))
-	if size == 0 {
-		size = 10
-	}
-	var s string
-
-	rd := &service.RouteGroupDao{}
-	routeGroupList := []service.RouteGroupDao{}
-	if search, exist := c.GetQuery("search"); exist && len(search) > 0 {
-		s = "%" + search + "%"
-	}
-	if err, count := rd.GetRouteGroupList(&routeGroupList, s, page, size); err != nil {
-		e := errno.FromMessage(errno.RouteGroupRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		result := &service.ListResponse{Count: count, Data: routeGroupList}
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
-
-func listRouteGroupName(c *gin.Context) {
-	db := conf.DB()
-	routeGroupList := []service.RouteGroupDao{}
-	var count int
-	if err := db.Order("name").Table("route_group").Find(&routeGroupList).Count(&count).Error; err != nil {
-		e := errno.FromMessage(errno.RouteGroupRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		responseList := make([]*service.RouteGroupNameResponse, 0)
-		for _, r := range routeGroupList {
-			response, err := r.Parse2NameResponse()
-			if err == nil {
-				responseList = append(responseList, response)
-			}
-		}
-		result := &service.ListResponse{Count: count, Data: responseList}
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
-
-func updateRouteGroup(c *gin.Context) {
-	// get params
-	gid := c.Param("gid")
-	param, exist := c.Get("requestBody")
-	if !exist || len(param.([]byte)) < 1 {
-		e := errno.FromMessage(errno.RouteRequestError, "route_group update with no post data")
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	// trans params
-	rr := &service.RouteGroupRequest{}
-	if err := rr.Parse(param); err != nil {
-		e := errno.FromMessage(errno.RouteGroupRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	rr.Id = gid
-	if ud, err := service.Trans2RouteGroupDao(rr); err != nil {
-		c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response())
-		return
-	} else {
-		// mysql
-		if err2 := ud.UpdateRouteGroup(); err2 != nil {
-			e := errno.FromMessage(errno.DBRouteGroupError, err2.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func deleteRouteGroup(c *gin.Context) {
-	gid := c.Param("gid")
-	// 参数校验
-	routeGroup := &service.RouteGroupDao{}
-	if err := conf.DB().Table("route_group").Where("id=?", gid).First(&routeGroup).Error; err != nil {
-		e := errno.FromMessage(errno.RouteGroupRequestError, err.Error()+" route_group ID: "+gid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	// delete from mysql
-	routeGroup.ID = uuid.FromStringOrNil(gid)
-	if err := routeGroup.DeleteRouteGroup(); err != nil {
-		e := errno.FromMessage(errno.DBRouteGroupDeleteError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
diff --git a/api/route/route_test.go b/api/route/route_test.go
deleted file mode 100644
index 5b66679..0000000
--- a/api/route/route_test.go
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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 route
-
-import (
-	"net/http"
-	"testing"
-)
-
-func TestRoute(t *testing.T) {
-	// create ok
-
-	testHandler.
-		Post(uriPrefix + "/routes").
-		JSON(`{
-      "id": "11",
-			"name": "e2e-test-route1",
-			"desc": "route created by java sdk",
-			"priority": 0,
-			"methods": [
-				"GET"
-			],
-			"uris": [
-				"/helloworld",
-				"/hello2*"
-			],
-			"hosts": [
-				"s.com"
-			],
-			"protocols": [
-				"http",
-				"https",
-				"websocket"
-			],
-			"redirect":{
-				"code": 302,
-				"uri": "/hello"
-			},
-			"vars": [
-				["arg_name", "==", "json"],
-				["arg_age", ">", "18"],
-				["arg_address", "~~", "China.*"]
-			],
-			"upstream": {
-				"type": "roundrobin",
-				"nodes": {
-					"39.97.63.215:80": 100
-				},
-				"timeout": {
-					"connect":15,
-					"send":15,
-					"read":15
-				}
-			},
-			"upstream_protocol": "keep",
-			"upstream_path": {
-				"type" : "static",
-				"from": "",
-				"to": "/hello"
-			},
-			"upstream_header": {
-				"header_name1": "header_value1",
-				"header_name2": "header_value2"
-			},
-			"plugins": {
-				"limit-count": {
-					"count": 2,
-					"time_window": 60,
-					"rejected_code": 503,
-					"key": "remote_addr"
-				},
-				"prometheus": {}
-			}
-		}`).
-		Headers(map[string]string{"Authorization": token}).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//update ok
-	testHandler.
-		Put(uriPrefix + "/routes/11").
-		JSON(`{
-      "id": "11",
-			"name": "e2e-test-route1",
-			"desc": "route created by java sdk",
-			"priority": 0,
-			"methods": [
-				"GET"
-			],
-			"uris": [
-				"/helloworld",
-				"/hello2*"
-			],
-			"hosts": [
-				"s.com"
-			],
-			"protocols": [
-				"http",
-				"https",
-				"websocket"
-			],
-			"redirect":{
-				"code": 302,
-				"uri": "/hello"
-			},
-			"vars": [
-				["arg_name", "==", "json"],
-				["arg_age", ">", "18"],
-				["arg_address", "~~", "China.*"]
-			],
-			"upstream": {
-				"type": "roundrobin",
-				"nodes": {
-					"39.97.63.215:80": 100
-				},
-				"timeout": {
-					"connect":15,
-					"send":15,
-					"read":15
-				}
-			},
-			"upstream_protocol": "keep",
-			"upstream_path": {
-				"type" : "static",
-				"from": "",
-				"to": "/hello"
-			},
-			"upstream_header": {
-				"header_name1": "header_value1",
-				"header_name2": "header_value2"
-			},
-			"plugins": {
-				"limit-count": {
-					"count": 2,
-					"time_window": 60,
-					"rejected_code": 503,
-					"key": "remote_addr"
-				},
-				"prometheus": {}
-			}
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//list
-	testHandler.
-		Get(uriPrefix + "/routes").
-		Headers(map[string]string{"Authorization": token}).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//not exist
-	testHandler.
-		Get(uriPrefix + "/notexist/routes").
-		//Query("name", "notexists").
-		QueryCollection(map[string][]string{"name": {"notexists"}}).
-		Headers(map[string]string{"Authorization": token}).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//existed todo: fix bug
-	//testHandler.
-	//	Get(uriPrefix + "/notexist/routes").
-	//	QueryCollection(map[string][]string{"name": {""}}).
-	//	Headers(map[string]string{"Authorization": token}).
-	//	Expect(t).
-	//	Status(http.StatusBadRequest).
-	//	End()
-
-	//delete
-	testHandler.
-		Delete(uriPrefix + "/routes/11").
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-}
diff --git a/api/route/ssl.go b/api/route/ssl.go
deleted file mode 100644
index d962be8..0000000
--- a/api/route/ssl.go
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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 route
-
-import (
-	"net/http"
-	"strconv"
-
-	"github.com/gin-gonic/gin"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/service"
-	uuid "github.com/satori/go.uuid"
-)
-
-func AppendSsl(r *gin.Engine) *gin.Engine {
-	r.POST("/apisix/admin/check_ssl_cert", sslCheck)
-	r.POST("/apisix/admin/check_ssl_exists", hostCheck)
-
-	r.GET("/apisix/admin/ssls", sslList)
-	r.POST("/apisix/admin/ssls", sslCreate)
-	r.GET("/apisix/admin/ssls/:id", sslItem)
-	r.PUT("/apisix/admin/ssls/:id", sslUpdate)
-	r.DELETE("/apisix/admin/ssls/:id", sslDelete)
-	r.PATCH("/apisix/admin/ssls/:id", sslPatch)
-
-	return r
-}
-
-func sslList(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
-	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
-	status, _ := strconv.Atoi(c.DefaultQuery("status", "-1"))
-	expireStart, _ := strconv.Atoi(c.DefaultQuery("expire_start", "-1"))
-	expireEnd, _ := strconv.Atoi(c.DefaultQuery("expire_end", "-1"))
-	sortType := c.DefaultQuery("sort_type", "desc")
-
-	sni := c.DefaultQuery("sni", "")
-
-	count, list, err := service.SslList(page, size, status, expireStart, expireEnd, sni, sortType)
-
-	if err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	resp := errno.FromMessage(errno.SystemSuccess).ListResponse(count, list)
-
-	c.JSON(http.StatusOK, resp)
-}
-
-func sslItem(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	id := c.Param("id")
-
-	ssl, err := service.SslItem(id)
-
-	if err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.FromMessage(errno.SystemSuccess).ItemResponse(ssl))
-}
-
-func sslCheck(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	ssl, err := service.SslCheck(param)
-	if err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	resp := errno.FromMessage(errno.SystemSuccess).ItemResponse(ssl)
-
-	c.JSON(http.StatusOK, resp)
-}
-
-func sslCreate(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-
-	u4 := uuid.NewV4()
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	if err := service.SslCreate(param, u4.String()); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
-
-func sslUpdate(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-	id := c.Param("id")
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	if err := service.SslUpdate(param, id); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
-
-func sslPatch(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-
-	id := c.Param("id")
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	if err := service.SslPatch(param, id); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
-
-func sslDelete(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	id := c.Param("id")
-
-	if err := service.SslDelete(id); err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-}
-
-func hostCheck(c *gin.Context) {
-	requestId, _ := c.Get("X-Request-Id")
-	param, exist := c.Get("requestBody")
-
-	if !exist || len(param.([]byte)) < 1 {
-		err := errno.New(errno.InvalidParam)
-		logger.WithField(conf.RequestId, requestId).Error(err.ErrorDetail())
-		c.AbortWithStatusJSON(http.StatusBadRequest, err.Response())
-		return
-	}
-
-	err := service.CheckSniExists(param)
-	if err != nil {
-		handleServiceError(c, requestId, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, errno.Succeed())
-
-}
diff --git a/api/route/ssl_test.go b/api/route/ssl_test.go
deleted file mode 100644
index 8c85ff3..0000000
--- a/api/route/ssl_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 route
-
-import (
-	"net/http"
-	"testing"
-)
-
-func TestSslCreate(t *testing.T) {
-	sslId := "ssl_id"
-	// ok
-	testHandler.
-		Post(uriPrefix + "/ssl").
-		JSON(`{
-      "id": "` + sslId + `"
-			"key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGO0J9xrOcmvgh\npkqHIYHCw35FTfIT5uXOSzdF49M2ZAKBQwFG0ovYT8bc0glNLB+hpDhJPL531qSP\nl1ZOe0W1ofP1u0T5Zzc9Rub/kn7RMPq0BsSC6J3rF+rQEwh1PM8qUuD8DxZ7jaOL\niMNL6SyuZIPsS1kPPBtsioukdo666tbjNMixhQbI9Wpg55abdXRFh3i7Zu/9siF1\njCGcsskjOaUOY4sYQ3i5WU/HIIRhA82XuIL+Sxd32P8bKi2UT1sqFXRjAVR7KRWo\nIVvkmSLoZb9ucV6MsccDrRYBf6rLbI1tFj9l2rY6GTFlT+6z7K/ZI60DGi/hsBfl\nDeEQ5WuxAgMBAAECggEAVHQQyucpxHGdfzCKlfGnh+Oj20Du/p2jkHUp [...]
-			"cert": "-----BEGIN CERTIFICATE-----\nMIIEVzCCAr+gAwIBAgIQITiNM7xmudhg3pK85KDwLDANBgkqhkiG9w0BAQsFADB/\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIWp1bnh1\nY2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTExMC8GA1UEAwwobWtjZXJ0IGp1\nbnh1Y2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTAeFw0xOTA2MDEwMDAwMDBa\nFw0zMDA3MDgwNzQ4MDJaMFUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBj\nZXJ0aWZpY2F0ZTEqMCgGA1UECwwhanVueHVjaGVuQGp1bnh1ZGVBaXIgKGp1bnh1\nIGNoZW4pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjt [...]
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//update ok
-	testHandler.
-		Put(uriPrefix + "/consumers/" + sslId).
-		JSON(`{
-      "id": "` + sslId + `"
-			"key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGO0J9xrOcmvgh\npkqHIYHCw35FTfIT5uXOSzdF49M2ZAKBQwFG0ovYT8bc0glNLB+hpDhJPL531qSP\nl1ZOe0W1ofP1u0T5Zzc9Rub/kn7RMPq0BsSC6J3rF+rQEwh1PM8qUuD8DxZ7jaOL\niMNL6SyuZIPsS1kPPBtsioukdo666tbjNMixhQbI9Wpg55abdXRFh3i7Zu/9siF1\njCGcsskjOaUOY4sYQ3i5WU/HIIRhA82XuIL+Sxd32P8bKi2UT1sqFXRjAVR7KRWo\nIVvkmSLoZb9ucV6MsccDrRYBf6rLbI1tFj9l2rY6GTFlT+6z7K/ZI60DGi/hsBfl\nDeEQ5WuxAgMBAAECggEAVHQQyucpxHGdfzCKlfGnh+Oj20Du/p2jkHUp [...]
-			"cert": "-----BEGIN CERTIFICATE-----\nMIIEVzCCAr+gAwIBAgIQITiNM7xmudhg3pK85KDwLDANBgkqhkiG9w0BAQsFADB/\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIWp1bnh1\nY2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTExMC8GA1UEAwwobWtjZXJ0IGp1\nbnh1Y2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTAeFw0xOTA2MDEwMDAwMDBa\nFw0zMDA3MDgwNzQ4MDJaMFUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBj\nZXJ0aWZpY2F0ZTEqMCgGA1UECwwhanVueHVjaGVuQGp1bnh1ZGVBaXIgKGp1bnh1\nIGNoZW4pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjt [...]
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//list
-	testHandler.
-		Get(uriPrefix + "/ssl").
-		Headers(map[string]string{"Authorization": token}).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//delete
-	testHandler.
-		Delete(uriPrefix + "/consumers/" + sslId).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-}
diff --git a/api/route/upstream.go b/api/route/upstream.go
deleted file mode 100644
index 0135a85..0000000
--- a/api/route/upstream.go
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * 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 route
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"strconv"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/service"
-	"github.com/gin-gonic/gin"
-	uuid "github.com/satori/go.uuid"
-)
-
-func AppendUpstream(r *gin.Engine) *gin.Engine {
-	r.POST("/apisix/admin/upstreams", createUpstream)
-	r.GET("/apisix/admin/upstreams/:uid", findUpstream)
-	r.GET("/apisix/admin/upstreams", listUpstream)
-	r.GET("/apisix/admin/names/upstreams", listUpstreamName)
-	r.PUT("/apisix/admin/upstreams/:uid", updateUpstream)
-	r.DELETE("/apisix/admin/upstreams/:uid", deleteUpstream)
-	r.GET("/apisix/admin/notexist/upstreams", isUpstreamExist)
-	return r
-}
-
-func isUpstreamExist(c *gin.Context) {
-	if name, exist := c.GetQuery("name"); exist {
-		db := conf.DB()
-		db = db.Table("upstreams")
-		exclude, exist := c.GetQuery("exclude")
-		if exist {
-			db = db.Where("name=? and id<>?", name, exclude)
-		} else {
-			db = db.Where("name=?", name)
-		}
-		var count int
-		if err := db.Count(&count).Error; err != nil {
-			e := errno.FromMessage(errno.UpstreamRequestError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			if count == 0 {
-				c.Data(http.StatusOK, service.ContentType, errno.Success())
-				return
-			} else {
-				e := errno.FromMessage(errno.DBUpstreamReduplicateError, name)
-				c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-				return
-			}
-		}
-	} else {
-		e := errno.FromMessage(errno.UpstreamRequestError, "name is needed")
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-}
-
-func listUpstreamName(c *gin.Context) {
-	size, _ := strconv.Atoi(c.Query("size"))
-	page, _ := strconv.Atoi(c.Query("page"))
-	db := conf.DB()
-	upstreamList := []service.UpstreamDao{}
-	var count int
-	if size == 0 || page == 0 {
-		db = db.Order("name").Table("upstreams")
-	} else {
-		db = db.Order("name").Table("upstreams").Offset((page - 1) * size).Limit(size)
-	}
-	if err := db.Find(&upstreamList).Count(&count).Error; err != nil {
-		e := errno.FromMessage(errno.UpstreamRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		responseList := make([]*service.UpstreamNameResponse, 0)
-		for _, r := range upstreamList {
-			response, err := r.Parse2NameResponse()
-			if err == nil {
-				responseList = append(responseList, response)
-			}
-		}
-		result := &service.ListResponse{Count: count, Data: responseList}
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
-
-func createUpstream(c *gin.Context) {
-	u4 := uuid.NewV4()
-	uid := u4.String()
-	// todo 参数校验
-	param, exist := c.Get("requestBody")
-	if !exist || len(param.([]byte)) < 1 {
-		e := errno.FromMessage(errno.RouteRequestError, "upstream create with no post data")
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	// trans params
-	ur := &service.UpstreamRequest{}
-	if err := ur.Parse(param); err != nil {
-		e := errno.FromMessage(errno.UpstreamRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	ur.Id = uid
-	fmt.Println(ur)
-	// mysql
-	if ud, err := service.Trans2UpstreamDao(nil, ur); err != nil {
-		c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response())
-		return
-	} else {
-		// transaction
-		db := conf.DB()
-		tx := db.Begin()
-		defer func() {
-			if r := recover(); r != nil {
-				tx.Rollback()
-			}
-		}()
-		if err := tx.Create(ud).Error; err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			// apisix
-			if aur, err := ur.Parse2Apisix(); err != nil {
-				tx.Rollback()
-				e := errno.FromMessage(errno.UpstreamTransError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-				return
-			} else {
-				if resp, err := aur.Create(); err != nil {
-					tx.Rollback()
-					if httpError, ok := err.(*errno.HttpError); ok {
-						c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-						return
-					} else {
-						e := errno.FromMessage(errno.ApisixUpstreamCreateError, err.Error())
-						logger.Error(e.Msg)
-						c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-						return
-					}
-				} else {
-					if err := tx.Commit().Error; err == nil {
-						if ud, err := service.Trans2UpstreamDao(resp, ur); err != nil {
-							e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-							logger.Error(e.Msg)
-						} else {
-							if err := conf.DB().Model(&service.UpstreamDao{}).Update(ud).Error; err != nil {
-								e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-								logger.Error(e.Msg)
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func findUpstream(c *gin.Context) {
-	uid := c.Param("uid")
-	upstream := &service.UpstreamDao{}
-	var count int
-	if err := conf.DB().Table("upstreams").Where("id=?", uid).Count(&count).Error; err != nil {
-		e := errno.FromMessage(errno.UpstreamRequestError, err.Error()+" upstream ID: "+uid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	} else {
-		if count < 1 {
-			e := errno.FromMessage(errno.UpstreamRequestError, " upstream ID: "+uid+" not exist")
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(e.Status, e.Response())
-			return
-		}
-	}
-	conf.DB().Table("upstreams").Where("id=?", uid).First(&upstream)
-	// find from apisix
-	aur := &service.ApisixUpstreamRequest{Id: uid}
-	if resp, err := aur.FindById(); err != nil {
-		e := errno.FromMessage(errno.UpstreamRequestError, err.Error()+" upstream ID: "+uid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		if result, err := resp.Parse2Request(); err != nil {
-			e := errno.FromMessage(errno.UpstreamRequestError, err.Error()+" upstream ID: "+uid)
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			resp, _ := json.Marshal(result)
-			c.Data(http.StatusOK, service.ContentType, resp)
-		}
-	}
-}
-
-func listUpstream(c *gin.Context) {
-	size, _ := strconv.Atoi(c.Query("size"))
-	page, _ := strconv.Atoi(c.Query("page"))
-	if size == 0 {
-		size = 10
-	}
-	db := conf.DB()
-	db = db.Table("upstreams")
-	if search, exist := c.GetQuery("search"); exist {
-		s := "%" + search + "%"
-		db = db.Where("name like ? or description like ? or nodes like ? ", s, s, s)
-	}
-	upstreamList := []service.UpstreamDao{}
-	var count int
-	if err := db.Order("update_time desc").Offset((page - 1) * size).Limit(size).Find(&upstreamList).Error; err != nil {
-		e := errno.FromMessage(errno.RouteRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		responseList := make([]*service.UpstreamResponse, 0)
-		for _, r := range upstreamList {
-			response, err := r.Parse2Response()
-			if err == nil {
-				responseList = append(responseList, response)
-			}
-		}
-		if err := db.Count(&count).Error; err != nil {
-			e := errno.FromMessage(errno.UpstreamRequestError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		}
-		result := &service.ListResponse{Count: count, Data: responseList}
-		resp, _ := json.Marshal(result)
-		c.Data(http.StatusOK, service.ContentType, resp)
-	}
-}
-func updateUpstream(c *gin.Context) {
-	uid := c.Param("uid")
-	param, exist := c.Get("requestBody")
-	if !exist || len(param.([]byte)) < 1 {
-		e := errno.FromMessage(errno.RouteRequestError, "upstream update with no post data")
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	// trans params
-	ur := &service.UpstreamRequest{}
-	if err := ur.Parse(param); err != nil {
-		e := errno.FromMessage(errno.UpstreamRequestError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	ur.Id = uid
-	// mysql
-	if ud, err := service.Trans2UpstreamDao(nil, ur); err != nil {
-		c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response())
-		return
-	} else {
-		// transaction
-		db := conf.DB()
-		tx := db.Begin()
-		defer func() {
-			if r := recover(); r != nil {
-				tx.Rollback()
-			}
-		}()
-		if err := tx.Model(&service.UpstreamDao{}).Update(ud).Error; err != nil {
-			tx.Rollback()
-			e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-			logger.Error(e.Msg)
-			c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-			return
-		} else {
-			// apisix
-			if aur, err := ur.Parse2Apisix(); err != nil {
-				tx.Rollback()
-				e := errno.FromMessage(errno.UpstreamTransError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-				return
-			} else {
-				if resp, err := aur.Update(); err != nil {
-					tx.Rollback()
-					if httpError, ok := err.(*errno.HttpError); ok {
-						c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-						return
-					} else {
-						e := errno.FromMessage(errno.ApisixUpstreamUpdateError, err.Error())
-						logger.Error(e.Msg)
-						c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-						return
-					}
-				} else {
-					if err := tx.Commit().Error; err == nil {
-						if ud, err := service.Trans2UpstreamDao(resp, ur); err != nil {
-							e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-							logger.Error(e.Msg)
-						} else {
-							if err := conf.DB().Model(&service.UpstreamDao{}).Update(ud).Error; err != nil {
-								e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-								logger.Error(e.Msg)
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
-
-func deleteUpstream(c *gin.Context) {
-	uid := c.Param("uid")
-	// 参数校验
-	upstream := &service.UpstreamDao{}
-	if err := conf.DB().Table("upstreams").Where("id=?", uid).First(&upstream).Error; err != nil {
-		e := errno.FromMessage(errno.UpstreamRequestError, err.Error()+" upstream ID: "+uid)
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusBadRequest, e.Response())
-		return
-	}
-	db := conf.DB()
-	tx := db.Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-	// delete from mysql
-	rd := &service.UpstreamDao{}
-	rd.ID = uuid.FromStringOrNil(uid)
-	if err := tx.Delete(rd).Error; err != nil {
-		tx.Rollback()
-		e := errno.FromMessage(errno.DBUpstreamDeleteError, err.Error())
-		logger.Error(e.Msg)
-		c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-		return
-	} else {
-		// delete from apisix
-		request := &service.ApisixUpstreamRequest{Id: uid}
-		if _, err := request.Delete(); err != nil {
-			tx.Rollback()
-			if httpError, ok := err.(*errno.HttpError); ok {
-				c.AbortWithStatusJSON(httpError.Code, httpError.Msg)
-				return
-			} else {
-				e := errno.FromMessage(errno.ApisixUpstreamDeleteError, err.Error())
-				logger.Error(e.Msg)
-				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
-				return
-			}
-		}
-	}
-	if err := tx.Commit().Error; err != nil {
-		e := errno.FromMessage(errno.ApisixUpstreamDeleteError, err.Error())
-		logger.Error(e.Msg)
-	}
-	c.Data(http.StatusOK, service.ContentType, errno.Success())
-}
diff --git a/api/script/db/schema.sql b/api/script/db/schema.sql
deleted file mode 100644
index 8c476c3..0000000
--- a/api/script/db/schema.sql
+++ /dev/null
@@ -1,71 +0,0 @@
--- this is a db script for init
-CREATE DATABASE `manager`;
-use `manager`;
-CREATE TABLE `routes` (
-  `id` varchar(64) NOT NULL unique,
-  `name` varchar(200) NOT NULL unique, -- not support yet
-  `description` varchar(200) DEFAULT NULL,
-  `hosts` text,
-  `uris` text,
-  `upstream_nodes` text,
-  `upstream_id` varchar(64) , -- fk
-  `priority` int NOT NULL DEFAULT 0,
-  `state` int NOT NULL DEFAULT 1, -- 1-normal 0-disable
-  `content` text,
-  `script` text,
-  `content_admin_api` text,
-  `create_time` bigint(20),
-  `update_time` bigint(20),
-  `route_group_id` varchar(64) NOT NULL,
-  `route_group_name` varchar(64) NOT NULL,
-  `status` tinyint(1),
-  PRIMARY KEY (`id`)
-) DEFAULT CHARSET=utf8;
-
-CREATE TABLE `ssls` (
-  `id` char(36) NOT NULL DEFAULT '',
-  `public_key` text NOT NULL,
-  `snis` text NOT NULL,
-  `validity_start` bigint(20) unsigned NOT NULL,
-  `validity_end` bigint(20) unsigned NOT NULL,
-  `status` tinyint(1) unsigned NOT NULL DEFAULT '1',
-  `create_time` bigint(20) unsigned NOT NULL,
-  `update_time` bigint(20) unsigned NOT NULL,
-  `public_key_hash` varchar(64) NOT NULL DEFAULT '',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uni_public_key_hash` (`public_key_hash`)
-) DEFAULT CHARSET=utf8;
-
--- upstream
-CREATE TABLE `upstreams` (
-  `id` varchar(64) NOT NULL unique,
-  `name` varchar(200) NOT NULL unique, -- not support
-  `description` varchar(200) DEFAULT NULL,
-  `nodes` text,
-  `content` text,
-  `content_admin_api` text,
-  `create_time` bigint(20),
-  `update_time` bigint(20),
-  PRIMARY KEY (`id`)
-) DEFAULT CHARSET=utf8;
-
-CREATE TABLE `consumers` (
-  `id` char(36) NOT NULL DEFAULT '',
-  `username` varchar(100) DEFAULT '',
-  `plugins` text,
-  `desc` varchar(200) DEFAULT '',
-  `create_time` int(10) unsigned NOT NULL,
-  `update_time` int(10) unsigned NOT NULL,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uni_username` (`username`)
-) DEFAULT CHARSET=utf8;
--- route_group
-CREATE TABLE `route_group` (
-  `id` varchar(64) NOT NULL unique,
-  `name` varchar(200) NOT NULL unique,
-  `description` varchar(200) DEFAULT NULL,
-  `create_time` bigint(20),
-  `update_time` bigint(20),
-
-  PRIMARY KEY (`id`)
-) DEFAULT CHARSET=utf8;
diff --git a/api/service/base.go b/api/service/base.go
deleted file mode 100644
index 8ed5f5c..0000000
--- a/api/service/base.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 service
-
-import (
-	"time"
-
-	"github.com/jinzhu/gorm"
-	uuid "github.com/satori/go.uuid"
-)
-
-// Base contains common columns for all tables.
-type Base struct {
-	ID         uuid.UUID `json:"id",sql:"type:uuid;primary_key;"`
-	CreateTime int64     `json:"create_time"`
-	UpdateTime int64     `json:"update_time"`
-}
-
-// BeforeCreate will set a UUID rather than numeric ID.
-func (base *Base) BeforeCreate(scope *gorm.Scope) error {
-	timestamp := time.Now().Unix()
-	err := scope.SetColumn("UpdateTime", timestamp)
-	err = scope.SetColumn("CreateTime", timestamp)
-	if len(base.ID) == 0 {
-		uuid := uuid.NewV4()
-		err = scope.SetColumn("ID", uuid)
-		return err
-	}
-	return err
-}
-
-func (base *Base) BeforeSave(scope *gorm.Scope) error {
-	err := scope.SetColumn("UpdateTime", time.Now().Unix())
-	return err
-}
diff --git a/api/service/consumer.go b/api/service/consumer.go
deleted file mode 100644
index 98dee45..0000000
--- a/api/service/consumer.go
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * 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 service
-
-import (
-	"encoding/json"
-	"fmt"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/utils"
-	uuid "github.com/satori/go.uuid"
-)
-
-type Consumer struct {
-	Base
-	Username string `json:"username"`
-	Desc     string `json:"desc"`
-	Plugins  string `json:"plugins"`
-}
-
-type ConsumerDto struct {
-	Base
-	Username string                 `json:"username"`
-	Desc     string                 `json:"desc"`
-	Plugins  map[string]interface{} `json:"plugins"`
-}
-
-type ApisixConsumer struct {
-	Username string                 `json:"username"`
-	Desc     string                 `json:"desc"`
-	Plugins  map[string]interface{} `json:"plugins"`
-}
-
-func (apisixConsumer *ApisixConsumer) Transfer(consumer *ConsumerDto) error {
-	apisixConsumer.Username = consumer.Username
-	apisixConsumer.Desc = consumer.Desc
-	apisixConsumer.Plugins = consumer.Plugins
-
-	return nil
-}
-
-func (consumer *Consumer) Transfer(req *ConsumerDto) error {
-	consumer.ID = req.ID
-	consumer.Desc = req.Desc
-	consumer.Username = req.Username
-
-	plugins, _ := json.Marshal(req.Plugins)
-	consumer.Plugins = string(plugins)
-
-	return nil
-}
-
-func (dto *ConsumerDto) Transfer(consumer *Consumer) error {
-	dto.ID = consumer.ID
-	dto.Desc = consumer.Desc
-	dto.Username = consumer.Username
-	dto.CreateTime = consumer.CreateTime
-	dto.UpdateTime = consumer.UpdateTime
-
-	var plugins map[string]interface{}
-	_ = json.Unmarshal([]byte(consumer.Plugins), &plugins)
-	dto.Plugins = plugins
-
-	return nil
-}
-
-// ApisixConsumerResponse is response from apisix admin api
-type ApisixConsumerResponse struct {
-	Action string        `json:"action"`
-	Node   *ConsumerNode `json:"node"`
-}
-
-type ConsumerNode struct {
-	Value         ApisixConsumer `json:"value"`
-	ModifiedIndex uint64         `json:"modifiedIndex"`
-}
-
-func (req *ConsumerDto) Parse(body interface{}) {
-	if err := json.Unmarshal(body.([]byte), req); err != nil {
-		req = nil
-	}
-}
-
-func ConsumerList(page, size int, search string) (int, []ConsumerDto, error) {
-	var count int
-	consumerList := []Consumer{}
-	db := conf.DB().Table("consumers")
-
-	if search != "" {
-		db = db.Where("username like ? ", "%"+search+"%").
-			Or("`desc` like ? ", "%"+search+"%")
-	}
-
-	if err := db.Order("create_time desc").Offset((page - 1) * size).Limit(size).Find(&consumerList).Error; err != nil {
-		e := errno.New(errno.DBReadError, err.Error())
-		return 0, nil, e
-	}
-	if err := db.Count(&count).Error; err != nil {
-		e := errno.New(errno.DBReadError, err.Error())
-		return 0, nil, e
-	}
-
-	dtoList := []ConsumerDto{}
-
-	for _, consumer := range consumerList {
-		dto := ConsumerDto{}
-		dto.Transfer(&consumer)
-
-		dtoList = append(dtoList, dto)
-	}
-
-	return count, dtoList, nil
-}
-
-func ConsumerItem(id string) (*ConsumerDto, error) {
-	if id == "" {
-		return nil, errno.New(errno.InvalidParam)
-	}
-
-	consumer := &Consumer{}
-	if err := conf.DB().Table("consumers").Where("id = ?", id).First(consumer).Error; err != nil {
-		e := errno.New(errno.DBReadError, err.Error())
-		return nil, e
-	}
-
-	dto := &ConsumerDto{}
-	dto.Transfer(consumer)
-
-	return dto, nil
-}
-
-func ConsumerCreate(param interface{}, id string) error {
-	req := &ConsumerDto{}
-	req.Parse(param)
-
-	if req.Username == "" {
-		return errno.New(errno.InvalidParamDetail, "username is required")
-	}
-
-	if len(req.Desc) > 200 {
-		return errno.New(errno.InvalidParamDetail, "description is too long")
-	}
-
-	exists := Consumer{}
-	conf.DB().Table("consumers").Where("username = ?", req.Username).First(&exists)
-	if exists != (Consumer{}) {
-		e := errno.New(errno.DuplicateUserName)
-		return e
-	}
-
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	consumer := &Consumer{}
-	consumer.Transfer(req)
-
-	// update mysql
-	consumer.ID = uuid.FromStringOrNil(id)
-	if err := tx.Create(consumer).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBWriteError, err.Error())
-	}
-
-	apisixConsumer := &ApisixConsumer{}
-	apisixConsumer.Transfer(req)
-
-	if _, err := apisixConsumer.PutConsumerToApisix(req.Username); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixSslCreateError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func ConsumerUpdate(param interface{}, id string) error {
-	if id == "" {
-		return errno.New(errno.InvalidParam)
-	}
-
-	req := &ConsumerDto{}
-	req.Parse(param)
-	if req == nil {
-		return errno.New(errno.InvalidParam)
-	}
-
-	req.ID = uuid.FromStringOrNil(id)
-	if req.Username != "" {
-		exists := Consumer{}
-		conf.DB().Table("consumers").Where("username = ?", req.Username).First(&exists)
-		if exists != (Consumer{}) && exists.ID != req.ID {
-			e := errno.New(errno.DuplicateUserName)
-			return e
-		}
-	}
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	// update mysql
-	consumer := &Consumer{}
-	consumer.Transfer(req)
-	data := Consumer{Desc: consumer.Desc, Plugins: consumer.Plugins}
-	if req.Username != "" {
-		data.Username = req.Username
-	}
-	if err := tx.Model(&consumer).Updates(data).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBWriteError, err.Error())
-	}
-
-	apisixConsumer := &ApisixConsumer{}
-	apisixConsumer.Transfer(req)
-
-	if _, err := apisixConsumer.PutConsumerToApisix(req.Username); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixConsumerUpdateError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func ConsumerDelete(id string) error {
-	if id == "" {
-		return errno.New(errno.InvalidParam)
-	}
-	//
-	consumer := &Consumer{}
-	if err := conf.DB().Table("consumers").Where("id = ?", id).First(consumer).Error; err != nil {
-		e := errno.New(errno.RecordNotExist, err.Error())
-		return e
-	}
-
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	// delete from mysql
-	if err := conf.DB().Delete(consumer).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBDeleteError, err.Error())
-	}
-
-	//delete from apisix
-	if _, err := consumer.DeleteConsumerFromApisix(); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixConsumerDeleteError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func (req *ApisixConsumer) PutConsumerToApisix(rid string) (*ApisixConsumerResponse, error) {
-	url := fmt.Sprintf("%s/consumers/%s", conf.BaseUrl, rid)
-	if data, err := json.Marshal(req); err != nil {
-		return nil, err
-	} else {
-		if resp, err := utils.Put(url, data); err != nil {
-			logger.Error(url)
-			logger.Error(string(data))
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixConsumerResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error(), resp)
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (req *Consumer) DeleteConsumerFromApisix() (*ApisixConsumerResponse, error) {
-	id := req.Username
-	url := fmt.Sprintf("%s/consumers/%s", conf.BaseUrl, id)
-
-	if resp, err := utils.Delete(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp ApisixConsumerResponse
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return &arresp, nil
-		}
-	}
-}
-
-func GetConsumerByUserName(name string) (*Consumer, error) {
-	if name == "" {
-		return nil, errno.New(errno.InvalidParam)
-	}
-	consumer := &Consumer{}
-	if err := conf.DB().Table("consumers").Where("username = ?", name).First(consumer).Error; err != nil {
-		e := errno.New(errno.NotFoundError, err.Error())
-		return nil, e
-	}
-
-	return consumer, nil
-}
diff --git a/api/service/plugin.go b/api/service/plugin.go
deleted file mode 100644
index 9ad7958..0000000
--- a/api/service/plugin.go
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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 service
-
-import (
-	"encoding/json"
-	"fmt"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/utils"
-)
-
-type ApisixPluginRequest struct {
-	Name string `json:"name"`
-}
-
-func (apr *ApisixPluginRequest) Schema() (map[string]interface{}, error) {
-	url := fmt.Sprintf("%s/schema/plugins/%s", conf.BaseUrl, apr.Name)
-	if resp, err := utils.Get(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		arresp := make(map[string]interface{})
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return arresp, nil
-		}
-	}
-}
-
-func (apr *ApisixPluginRequest) List() ([]string, error) {
-
-	url := fmt.Sprintf("%s/plugins/list", conf.BaseUrl)
-	if resp, err := utils.Get(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp []string
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return arresp, nil
-		}
-	}
-}
diff --git a/api/service/route.go b/api/service/route.go
deleted file mode 100644
index edea8e2..0000000
--- a/api/service/route.go
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * 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 service
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"os/exec"
-	"strings"
-	"time"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/log"
-	"github.com/apisix/manager-api/utils"
-	uuid "github.com/satori/go.uuid"
-)
-
-const (
-	ContentType      = "application/json"
-	HTTP             = "http"
-	HTTPS            = "https"
-	SCHEME           = "scheme"
-	WEBSOCKET        = "websocket"
-	REDIRECT         = "redirect"
-	PROXY_REWRIETE   = "proxy-rewrite"
-	UPATHTYPE_STATIC = "static"
-	UPATHTYPE_REGX   = "regx"
-	UPATHTYPE_KEEP   = "keep"
-)
-
-var logger = log.GetLogger()
-
-func (r *RouteRequest) Parse(body interface{}) error {
-	if err := json.Unmarshal(body.([]byte), r); err != nil {
-		r = nil
-		return err
-	} else {
-		if r.Uris == nil || len(r.Uris) < 1 {
-			r.Uris = []string{"/*"}
-		}
-		if len(strings.Trim(r.RouteGroupId, "")) > 0 {
-			routeGroup := &RouteGroupDao{}
-			if err, _ := routeGroup.FindRouteGroup(r.RouteGroupId); err != nil {
-				return err
-			}
-			r.RouteGroupName = routeGroup.Name
-		}
-	}
-	return nil
-}
-
-func (arr *ApisixRouteRequest) Parse(r *RouteRequest) {
-	arr.Desc = r.Desc
-	arr.Priority = r.Priority
-	arr.Methods = r.Methods
-	arr.Uris = r.Uris
-	arr.Hosts = r.Hosts
-	arr.Vars = r.Vars
-	arr.Upstream = r.Upstream
-	arr.Plugins = r.Plugins
-}
-
-func (rd *Route) Parse(r *RouteRequest, arr *ApisixRouteRequest) error {
-	//rd.Name = arr.Name
-	rd.Description = arr.Desc
-	rd.UpstreamId = r.UpstreamId
-	rd.RouteGroupId = r.RouteGroupId
-	rd.RouteGroupName = r.RouteGroupName
-	rd.Status = r.Status
-	if content, err := json.Marshal(r); err != nil {
-		return err
-	} else {
-		rd.Content = string(content)
-	}
-	if script, err := json.Marshal(r.Script); err != nil {
-		return err
-	} else {
-		rd.Script = string(script)
-	}
-	timestamp := time.Now().Unix()
-	rd.CreateTime = timestamp
-	rd.Priority = r.Priority
-	return nil
-}
-
-func (arr *ApisixRouteRequest) FindById(rid string) (*ApisixRouteResponse, error) {
-	url := fmt.Sprintf("%s/routes/%s", conf.BaseUrl, rid)
-	if resp, err := utils.Get(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp ApisixRouteResponse
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return &arresp, nil
-		}
-	}
-}
-
-func (arr *ApisixRouteRequest) Update(rid string) (*ApisixRouteResponse, error) {
-	url := fmt.Sprintf("%s/routes/%s", conf.BaseUrl, rid)
-	if b, err := json.Marshal(arr); err != nil {
-		return nil, err
-	} else {
-		fmt.Println(string(b))
-		if resp, err := utils.Put(url, b); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixRouteResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error())
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (arr *ApisixRouteRequest) Create(rid string) (*ApisixRouteResponse, error) {
-	url := fmt.Sprintf("%s/routes/%s", conf.BaseUrl, rid)
-	if b, err := json.Marshal(arr); err != nil {
-		return nil, err
-	} else {
-		fmt.Println(string(b))
-		if resp, err := utils.Put(url, b); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixRouteResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error())
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (arr *ApisixRouteRequest) Delete(rid string) (*ApisixRouteResponse, error) {
-	url := fmt.Sprintf("%s/routes/%s", conf.BaseUrl, rid)
-	if resp, err := utils.Delete(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp ApisixRouteResponse
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return &arresp, nil
-		}
-	}
-}
-
-type RouteRequest struct {
-	ID               string                 `json:"id,omitempty"`
-	Name             string                 `json:"name"`
-	Desc             string                 `json:"desc,omitempty"`
-	Priority         int64                  `json:"priority,omitempty"`
-	Methods          []string               `json:"methods,omitempty"`
-	Uris             []string               `json:"uris"`
-	Hosts            []string               `json:"hosts,omitempty"`
-	Protocols        []string               `json:"protocols,omitempty"`
-	Redirect         *Redirect              `json:"redirect,omitempty"`
-	Vars             [][]string             `json:"vars,omitempty"`
-	Upstream         *Upstream              `json:"upstream,omitempty"`
-	UpstreamId       string                 `json:"upstream_id,omitempty"`
-	UpstreamProtocol string                 `json:"upstream_protocol,omitempty"`
-	UpstreamPath     *UpstreamPath          `json:"upstream_path,omitempty"`
-	UpstreamHeader   map[string]string      `json:"upstream_header,omitempty"`
-	Plugins          map[string]interface{} `json:"plugins"`
-	Script           map[string]interface{} `json:"script"`
-	RouteGroupId     string                 `json:"route_group_id"`
-	RouteGroupName   string                 `json:"route_group_name"`
-	Status           bool                   `json:"status"`
-}
-
-func (r *ApisixRouteResponse) Parse() (*RouteRequest, error) {
-	o := r.Node.Value
-
-	//Protocols from vars and upstream
-	protocols := make([]string, 0)
-	if o.Upstream != nil && o.Upstream.EnableWebsocket {
-		protocols = append(protocols, WEBSOCKET)
-	}
-	if o.UpstreamId != "" {
-		protocols = append(protocols, WEBSOCKET)
-	}
-	flag := true
-	for _, t := range o.Vars {
-		if t[0] == SCHEME {
-			flag = false
-			protocols = append(protocols, t[2])
-		}
-	}
-	if flag {
-		protocols = append(protocols, HTTP)
-		protocols = append(protocols, HTTPS)
-	}
-	//Redirect from plugins
-	redirect := &Redirect{}
-	upstreamProtocol := UPATHTYPE_KEEP
-	upstreamHeader := make(map[string]string)
-	upstreamPath := &UpstreamPath{}
-	for k, v := range o.Plugins {
-		if k == REDIRECT {
-			if bytes, err := json.Marshal(v); err != nil {
-				return nil, err
-			} else {
-				if err := json.Unmarshal(bytes, redirect); err != nil {
-					return nil, err
-				}
-			}
-
-		}
-		if k == PROXY_REWRIETE {
-			pr := &ProxyRewrite{}
-			if bytes, err := json.Marshal(v); err != nil {
-				return nil, err
-			} else {
-				if err := json.Unmarshal(bytes, pr); err != nil {
-					return nil, err
-				} else {
-					if pr.Scheme != "" {
-						upstreamProtocol = pr.Scheme
-					}
-					upstreamHeader = pr.Headers
-					if (pr.RegexUri == nil || len(pr.RegexUri) < 2) && pr.Uri == "" {
-						upstreamPath = nil
-					} else if pr.RegexUri == nil || len(pr.RegexUri) < 2 {
-						upstreamPath.UPathType = UPATHTYPE_STATIC
-						upstreamPath.To = pr.Uri
-					} else {
-						upstreamPath.UPathType = UPATHTYPE_REGX
-						upstreamPath.From = pr.RegexUri[0]
-						upstreamPath.To = pr.RegexUri[1]
-					}
-				}
-			}
-		}
-	}
-	//Vars
-	requestVars := make([][]string, 0)
-	for _, t := range o.Vars {
-		if t[0] != SCHEME {
-			requestVars = append(requestVars, t)
-		}
-	}
-	//Plugins
-	requestPlugins := utils.CopyMap(o.Plugins)
-	delete(requestPlugins, REDIRECT)
-	delete(requestPlugins, PROXY_REWRIETE)
-
-	// check if upstream is not exist
-	if o.Upstream == nil && o.UpstreamId == "" {
-		upstreamProtocol = ""
-		upstreamHeader = nil
-		upstreamPath = nil
-	}
-	if upstreamPath != nil && upstreamPath.UPathType == "" {
-		upstreamPath = nil
-	}
-	result := &RouteRequest{
-		ID:               o.Id,
-		Desc:             o.Desc,
-		Priority:         o.Priority,
-		Methods:          o.Methods,
-		Uris:             o.Uris,
-		Hosts:            o.Hosts,
-		Redirect:         redirect,
-		Upstream:         o.Upstream,
-		UpstreamId:       o.UpstreamId,
-		RouteGroupId:     o.RouteGroupId,
-		UpstreamProtocol: upstreamProtocol,
-		UpstreamPath:     upstreamPath,
-		UpstreamHeader:   upstreamHeader,
-		Protocols:        protocols,
-		Vars:             requestVars,
-		Plugins:          requestPlugins,
-	}
-	return result, nil
-}
-
-type Redirect struct {
-	HttpToHttps bool   `json:"http_to_https,omitempty"`
-	Code        int64  `json:"code,omitempty"`
-	Uri         string `json:"uri,omitempty"`
-}
-
-type ProxyRewrite struct {
-	Uri      string            `json:"uri"`
-	RegexUri []string          `json:"regex_uri"`
-	Scheme   string            `json:"scheme"`
-	Host     string            `json:"host"`
-	Headers  map[string]string `json:"headers"`
-}
-
-func (r ProxyRewrite) MarshalJSON() ([]byte, error) {
-	m := make(map[string]interface{})
-	if r.RegexUri != nil {
-		m["regex_uri"] = r.RegexUri
-	}
-	if r.Uri != "" {
-		m["uri"] = r.Uri
-	}
-	if r.Scheme != UPATHTYPE_KEEP && r.Scheme != "" {
-		m["scheme"] = r.Scheme
-	}
-	if r.Host != "" {
-		m["host"] = r.Host
-	}
-	if r.Headers != nil && len(r.Headers) > 0 {
-		m["headers"] = r.Headers
-	}
-	if result, err := json.Marshal(m); err != nil {
-		return nil, err
-	} else {
-		return result, nil
-	}
-}
-
-func (r Redirect) MarshalJSON() ([]byte, error) {
-	m := make(map[string]interface{})
-	if r.HttpToHttps {
-		m["http_to_https"] = true
-	} else if r.Uri != "" {
-		m["code"] = r.Code
-		m["uri"] = r.Uri
-	}
-	if result, err := json.Marshal(m); err != nil {
-		return nil, err
-	} else {
-		return result, nil
-	}
-}
-
-type Upstream struct {
-	UType           string                 `json:"type"`
-	Nodes           map[string]int64       `json:"nodes"`
-	Timeout         UpstreamTimeout        `json:"timeout"`
-	EnableWebsocket bool                   `json:"enable_websocket"`
-	Checks          map[string]interface{} `json:"checks,omitempty"`
-	HashOn          string                 `json:"hash_on,omitempty"`
-	Key             string                 `json:"key,omitempty"`
-}
-
-type UpstreamTimeout struct {
-	Connect int64 `json:"connect"`
-	Send    int64 `json:"send"`
-	Read    int64 `json:"read"`
-}
-
-type UpstreamPath struct {
-	UPathType string `json:"type"`
-	From      string `json:"from"`
-	To        string `json:"to"`
-}
-
-type ApisixRouteRequest struct {
-	Desc       string                 `json:"desc,omitempty"`
-	Priority   int64                  `json:"priority"`
-	Methods    []string               `json:"methods,omitempty"`
-	Uris       []string               `json:"uris,omitempty"`
-	Hosts      []string               `json:"hosts,omitempty"`
-	Vars       [][]string             `json:"vars,omitempty"`
-	Upstream   *Upstream              `json:"upstream,omitempty"`
-	UpstreamId string                 `json:"upstream_id,omitempty"`
-	Plugins    map[string]interface{} `json:"plugins,omitempty"`
-	Script     string                 `json:"script,omitempty"`
-	//Name     string                 `json:"name"`
-}
-
-// ApisixRouteResponse is response from apisix admin api
-type ApisixRouteResponse struct {
-	Action string `json:"action"`
-	Node   *Node  `json:"node"`
-}
-
-type Node struct {
-	Value         Value  `json:"value"`
-	ModifiedIndex uint64 `json:"modifiedIndex"`
-}
-
-type Value struct {
-	Id             string                 `json:"id"`
-	Name           string                 `json:"name"`
-	Desc           string                 `json:"desc,omitempty"`
-	Priority       int64                  `json:"priority"`
-	Methods        []string               `json:"methods"`
-	Uris           []string               `json:"uris"`
-	Hosts          []string               `json:"hosts"`
-	Vars           [][]string             `json:"vars"`
-	Upstream       *Upstream              `json:"upstream,omitempty"`
-	UpstreamId     string                 `json:"upstream_id,omitempty"`
-	Plugins        map[string]interface{} `json:"plugins"`
-	RouteGroupId   string                 `json:"route_group_id"`
-	RouteGroupName string                 `json:"route_group_name"`
-	Status         bool                   `json:"status"`
-}
-
-type Route struct {
-	Base
-	Name            string `json:"name"`
-	Description     string `json:"description,omitempty"`
-	Hosts           string `json:"hosts"`
-	Uris            string `json:"uris"`
-	UpstreamNodes   string `json:"upstream_nodes"`
-	UpstreamId      string `json:"upstream_id"`
-	Priority        int64  `json:"priority"`
-	Content         string `json:"content"`
-	Script          string `json:"script"`
-	ContentAdminApi string `json:"content_admin_api"`
-	RouteGroupId    string `json:"route_group_id"`
-	RouteGroupName  string `json:"route_group_name"`
-	Status          bool   `json:"status"`
-}
-
-type RouteResponse struct {
-	Base
-	Name           string    `json:"name"`
-	Description    string    `json:"description,omitempty"`
-	Hosts          []string  `json:"hosts,omitempty"`
-	Uris           []string  `json:"uris,omitempty"`
-	Upstream       *Upstream `json:"upstream,omitempty"`
-	UpstreamId     string    `json:"upstream_id,omitempty"`
-	Priority       int64     `json:"priority"`
-	RouteGroupId   string    `json:"route_group_id"`
-	RouteGroupName string    `json:"route_group_name"`
-	Status         bool      `json:"status"`
-}
-
-type ListResponse struct {
-	Count int         `json:"count"`
-	Data  interface{} `json:"data"`
-}
-
-func (rr *RouteResponse) Parse(r *Route) {
-	rr.Base = r.Base
-	rr.Name = r.Name
-	rr.Description = r.Description
-	rr.UpstreamId = r.UpstreamId
-	rr.Priority = r.Priority
-	rr.RouteGroupId = r.RouteGroupId
-	rr.RouteGroupName = r.RouteGroupName
-	rr.Status = r.Status
-	// hosts
-	if len(r.Hosts) > 0 {
-		var hosts []string
-		if err := json.Unmarshal([]byte(r.Hosts), &hosts); err == nil {
-			rr.Hosts = hosts
-		} else {
-			logger.Error(err.Error())
-		}
-	}
-
-	// uris
-	if len(r.Uris) > 0 {
-		var uris []string
-		if err := json.Unmarshal([]byte(r.Uris), &uris); err == nil {
-			rr.Uris = uris
-		}
-	}
-
-	// uris
-	var resp ApisixRouteResponse
-	if err := json.Unmarshal([]byte(r.ContentAdminApi), &resp); err == nil {
-		rr.Upstream = resp.Node.Value.Upstream
-	}
-}
-
-// RouteRequest -> ApisixRouteRequest
-func ToApisixRequest(routeRequest *RouteRequest) *ApisixRouteRequest {
-	// redirect -> plugins
-	plugins := utils.CopyMap(routeRequest.Plugins)
-	redirect := routeRequest.Redirect
-	if redirect != nil {
-		plugins["redirect"] = redirect
-	}
-
-	logger.Info(routeRequest.Plugins)
-
-	// scheme https and not http -> vars ['scheme', '==', 'https']
-	pMap := utils.Set2Map(routeRequest.Protocols)
-
-	arr := &ApisixRouteRequest{}
-	arr.Parse(routeRequest)
-
-	// protocols[websokect] -> upstream
-	if pMap[WEBSOCKET] == 1 && arr.Upstream != nil {
-		arr.Upstream.EnableWebsocket = true
-	}
-	vars := utils.CopyStrings(routeRequest.Vars)
-	if pMap[HTTP] != 1 || pMap[HTTPS] != 1 {
-		if pMap[HTTP] == 1 {
-			vars = append(vars, []string{SCHEME, "==", HTTP})
-		}
-		if pMap[HTTPS] == 1 {
-			vars = append(vars, []string{SCHEME, "==", HTTPS})
-		}
-	}
-	if len(vars) > 0 {
-		arr.Vars = vars
-	} else {
-		arr.Vars = nil
-	}
-	// upstreamId
-	arr.UpstreamId = routeRequest.UpstreamId
-	// upstream protocol
-	if arr.Upstream != nil || arr.UpstreamId != "" {
-		pr := &ProxyRewrite{}
-		pr.Scheme = routeRequest.UpstreamProtocol
-		// upstream path
-		proxyPath := routeRequest.UpstreamPath
-		if proxyPath != nil {
-			if proxyPath.UPathType == UPATHTYPE_STATIC || proxyPath.UPathType == "" {
-				pr.Uri = proxyPath.To
-				pr.RegexUri = nil
-			} else {
-				pr.RegexUri = []string{proxyPath.From, proxyPath.To}
-			}
-		}
-		// upstream headers
-		pr.Headers = routeRequest.UpstreamHeader
-		if proxyPath != nil || pr.Scheme != UPATHTYPE_KEEP || (pr.Headers != nil && len(pr.Headers) > 0) {
-			plugins[PROXY_REWRIETE] = pr
-		}
-	}
-
-	if plugins != nil && len(plugins) > 0 {
-		arr.Plugins = plugins
-	} else {
-		arr.Plugins = nil
-	}
-
-	if routeRequest.Script != nil {
-		arr.Script, _ = generateLuaCode(routeRequest.Script)
-	}
-
-	return arr
-}
-
-func generateLuaCode(script map[string]interface{}) (string, error) {
-	scriptString, err := json.Marshal(script)
-	if err != nil {
-		return "", err
-	}
-
-	cmd := exec.Command("sh", "-c",
-		"cd /go/manager-api/dag-to-lua/ && lua cli.lua "+
-			"'"+string(scriptString)+"'")
-
-	logger.Info("generate conf:", string(scriptString))
-
-	stdout, _ := cmd.StdoutPipe()
-	defer stdout.Close()
-	if err := cmd.Start(); err != nil {
-		logger.Info("generate err:", err)
-		return "", err
-	}
-
-	result, _ := ioutil.ReadAll(stdout)
-	resData := string(result)
-
-	logger.Info("generated code:", resData)
-
-	return resData, nil
-}
-
-func ToRoute(routeRequest *RouteRequest,
-	arr *ApisixRouteRequest,
-	u4 uuid.UUID,
-	resp *ApisixRouteResponse) (*Route, *errno.ManagerError) {
-	rd := &Route{}
-	if err := rd.Parse(routeRequest, arr); err != nil {
-		e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-		return nil, e
-	}
-	if rd.Name == "" {
-		rd.Name = routeRequest.Name
-	}
-	rd.ID = u4
-	// content_admin_api
-	if resp != nil {
-		resp.Node.Value.RouteGroupId = rd.RouteGroupId
-		resp.Node.Value.Status = rd.Status
-		if respStr, err := json.Marshal(resp); err != nil {
-			e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-			return nil, e
-		} else {
-			rd.ContentAdminApi = string(respStr)
-		}
-	}
-	// hosts
-	hosts := routeRequest.Hosts
-	if hb, err := json.Marshal(hosts); err != nil {
-		e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-		logger.Warn(e.Msg)
-	} else {
-		rd.Hosts = string(hb)
-	}
-	// uris
-	uris := routeRequest.Uris
-	if ub, err := json.Marshal(uris); err != nil {
-		e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-		logger.Warn(e.Msg)
-	} else {
-		rd.Uris = string(ub)
-	}
-	// upstreamNodes
-	if routeRequest.Upstream != nil {
-		nodes := routeRequest.Upstream.Nodes
-		ips := make([]string, 0)
-		for k, _ := range nodes {
-			ips = append(ips, k)
-		}
-		if nb, err := json.Marshal(ips); err != nil {
-			e := errno.FromMessage(errno.DBRouteCreateError, err.Error())
-			logger.Warn(e.Msg)
-		} else {
-			rd.UpstreamNodes = string(nb)
-		}
-	}
-	// upstreamId
-	rd.UpstreamId = arr.UpstreamId
-	return rd, nil
-}
diff --git a/api/service/route_group.go b/api/service/route_group.go
deleted file mode 100644
index 8eb9a4d..0000000
--- a/api/service/route_group.go
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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 service
-
-import (
-	"encoding/json"
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	uuid "github.com/satori/go.uuid"
-)
-
-type RouteGroupDao struct {
-	Base
-	Name        string `json:"name"`
-	Description string `json:"description,omitempty"`
-}
-
-func (RouteGroupDao) TableName() string {
-	return "route_group"
-}
-
-func (rd *RouteGroupDao) CreateRouteGroup() error {
-	return conf.DB().Create(&rd).Error
-}
-
-func (rd *RouteGroupDao) FindRouteGroup(id string) (error, int) {
-	var count int
-	if err := conf.DB().Table("route_group").Where("id=?", id).Count(&count).Error; err != nil {
-		return err, 0
-	}
-	conf.DB().Table("route_group").Where("id=?", id).First(&rd)
-	return nil, count
-}
-
-func (rd *RouteGroupDao) GetRouteGroupList(routeGroupList *[]RouteGroupDao, search string, page, size int) (error, int) {
-	db := conf.DB()
-	db = db.Table(rd.TableName())
-	if len(search) != 0 {
-		db = db.Where("name like ? or description like ? ", search, search)
-	}
-	var count int
-	if err := db.Order("update_time desc").Offset((page - 1) * size).Limit(size).Find(&routeGroupList).Error; err != nil {
-		return err, 0
-	} else {
-		if err := db.Count(&count).Error; err != nil {
-			return err, 0
-		}
-		return nil, count
-	}
-}
-
-func (rd *RouteGroupDao) UpdateRouteGroup() error {
-	db := conf.DB()
-	tx := db.Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-	if err := tx.Model(&RouteGroupDao{}).Update(rd).Error; err != nil {
-		tx.Rollback()
-		return err
-	}
-	if err := tx.Table("routes").Where("route_group_id = ?", rd.ID.String()).Update("route_group_name", rd.Name).Error; err != nil {
-		tx.Rollback()
-		return err
-	}
-	if err := tx.Commit().Error; err != nil {
-		tx.Rollback()
-		return err
-	}
-	return nil
-}
-
-func (rd *RouteGroupDao) DeleteRouteGroup() error {
-	if err, count := rd.FindRoute(); err != nil {
-		e := errno.FromMessage(errno.RouteGroupSelectRoutesError, err.Error())
-		logger.Error(e.Msg)
-		return e
-	} else {
-		if count > 0 {
-			e := errno.FromMessage(errno.RouteGroupHasRoutesError)
-			logger.Error(e.Msg)
-			return e
-		}
-	}
-	return conf.DB().Delete(&rd).Error
-}
-
-type RouteGroupNameResponse struct {
-	ID   string `json:"id"`
-	Name string `json:"name"`
-}
-
-func (u *RouteGroupDao) Parse2NameResponse() (*RouteGroupNameResponse, error) {
-	// routeGroup
-	unr := &RouteGroupNameResponse{
-		ID:   u.ID.String(),
-		Name: u.Name,
-	}
-	return unr, nil
-}
-
-type RouteGroupRequest struct {
-	Id          string `json:"id,omitempty"`
-	Name        string `json:"name"`
-	Description string `json:"description"`
-}
-
-func (u *RouteGroupRequest) toJson() []byte {
-	res, _ := json.Marshal(&u)
-	return res
-}
-
-func (r *RouteGroupRequest) Parse(body interface{}) error {
-	if err := json.Unmarshal(body.([]byte), r); err != nil {
-		r = nil
-		return err
-	}
-	return nil
-}
-
-func Trans2RouteGroupDao(r *RouteGroupRequest) (*RouteGroupDao, *errno.ManagerError) {
-
-	u := &RouteGroupDao{
-		Name:        r.Name,
-		Description: r.Description,
-	}
-	// id
-	u.ID = uuid.FromStringOrNil(r.Id)
-	return u, nil
-}
-
-func (r *RouteGroupDao) FindRoute() (error, int) {
-	var count int
-	if err := conf.DB().Table("routes").Where("route_group_id=?", r.ID).Count(&count).Error; err != nil {
-		return err, 0
-	}
-	return nil, count
-}
diff --git a/api/service/ssl.go b/api/service/ssl.go
deleted file mode 100644
index 2fbfbfd..0000000
--- a/api/service/ssl.go
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * 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 service
-
-import (
-	"crypto/md5"
-	"crypto/tls"
-	"crypto/x509"
-	"encoding/json"
-	"encoding/pem"
-	"errors"
-	"fmt"
-	"regexp"
-	"strings"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/utils"
-	uuid "github.com/satori/go.uuid"
-)
-
-type Ssl struct {
-	Base
-	ValidityStart uint64 `json:"validity_start"`
-	ValidityEnd   uint64 `json:"validity_end"`
-	Snis          string `json:"snis"`
-	Status        uint64 `json:"status"`
-	PublicKey     string `json:"public_key,omitempty"`
-	PublicKeyHash string `json:"public_key_hash,omitempty"`
-}
-
-type SslDto struct {
-	Base
-	ValidityStart uint64   `json:"validity_start"`
-	ValidityEnd   uint64   `json:"validity_end"`
-	Snis          []string `json:"snis"`
-	Status        uint64   `json:"status"`
-	PublicKey     string   `json:"public_key,omitempty"`
-}
-
-type SslRequest struct {
-	ID         string   `json:"id,omitempty"`
-	PublicKey  string   `json:"cert,omitempty"`
-	PrivateKey string   `json:"key,omitempty"`
-	Snis       []string `json:"snis,omitempty"`
-	Status     uint64   `json:"status,omitempty"`
-}
-
-// ApisixSslResponse is response from apisix admin api
-type ApisixSslResponse struct {
-	Action string   `json:"action"`
-	Node   *SslNode `json:"node"`
-}
-
-type SslNode struct {
-	Value         SslRequest `json:"value"`
-	ModifiedIndex uint64     `json:"modifiedIndex"`
-}
-
-func (req *SslRequest) Parse(body interface{}) {
-	if err := json.Unmarshal(body.([]byte), req); err != nil {
-		logger.Info("req:")
-		logger.Info(req)
-		req = nil
-	}
-}
-
-func (sslDto *SslDto) Parse(ssl *Ssl) error {
-	sslDto.ID = ssl.ID
-	sslDto.ValidityStart = ssl.ValidityStart
-	sslDto.ValidityEnd = ssl.ValidityEnd
-
-	var snis []string
-	_ = json.Unmarshal([]byte(ssl.Snis), &snis)
-	sslDto.Snis = snis
-
-	sslDto.Status = ssl.Status
-	sslDto.PublicKey = ssl.PublicKey
-	sslDto.CreateTime = ssl.CreateTime
-	sslDto.UpdateTime = ssl.UpdateTime
-
-	return nil
-}
-
-func SslList(page, size, status, expireStart, expireEnd int, sni, sortType string) (int, []SslDto, error) {
-	var count int
-	sslList := []Ssl{}
-	db := conf.DB().Table("ssls")
-
-	if sni != "" {
-		db = db.Where("snis like ? ", "%"+sni+"%")
-	}
-	if status > -1 {
-		db = db.Where("status = ? ", status)
-	}
-	if expireStart > 0 {
-		db = db.Where("validity_end >= ? ", expireStart)
-	}
-	if expireEnd > 0 {
-		db = db.Where("validity_end <= ? ", expireEnd)
-	}
-
-	sortType = strings.ToLower(sortType)
-	if sortType != "desc" {
-		sortType = "asc"
-	}
-
-	if err := db.Order("validity_end " + sortType).Offset((page - 1) * size).Limit(size).Find(&sslList).Error; err != nil {
-		e := errno.New(errno.DBReadError, err.Error())
-		return 0, nil, e
-	}
-	if err := db.Count(&count).Error; err != nil {
-		e := errno.New(errno.DBReadError, err.Error())
-		return 0, nil, e
-	}
-
-	sslDtoList := []SslDto{}
-
-	for _, ssl := range sslList {
-		sslDto := SslDto{}
-		sslDto.Parse(&ssl)
-
-		sslDtoList = append(sslDtoList, sslDto)
-	}
-
-	return count, sslDtoList, nil
-}
-
-func SslItem(id string) (*SslDto, error) {
-	if id == "" {
-		return nil, errno.New(errno.InvalidParam)
-	}
-	ssl := &Ssl{}
-
-	if err := conf.DB().Table("ssls").Where("id = ?", id).First(ssl).Error; err != nil {
-		e := errno.New(errno.DBReadError, err.Error())
-		return nil, e
-	}
-
-	sslDto := &SslDto{}
-	sslDto.Parse(ssl)
-
-	return sslDto, nil
-}
-
-func SslCheck(param interface{}) (*SslDto, error) {
-	sslReq := &SslRequest{}
-	sslReq.Parse(param)
-
-	ssl, err := ParseCert(sslReq.PublicKey, sslReq.PrivateKey)
-
-	if err != nil {
-		e := errno.FromMessage(errno.SslParseError, err.Error())
-		return nil, e
-	}
-
-	ssl.PublicKey = ""
-
-	sslDto := &SslDto{}
-	sslDto.Parse(ssl)
-
-	return sslDto, nil
-}
-
-func SslCreate(param interface{}, id string) error {
-	sslReq := &SslRequest{}
-	sslReq.Parse(param)
-
-	if sslReq.PrivateKey == "" {
-		return errno.New(errno.InvalidParamDetail, "Key is required")
-	}
-	if sslReq.PublicKey == "" {
-		return errno.New(errno.InvalidParamDetail, "Cert is required")
-	}
-
-	sslReq.PublicKey = strings.TrimSpace(sslReq.PublicKey)
-	sslReq.PrivateKey = strings.TrimSpace(sslReq.PrivateKey)
-
-	ssl, err := ParseCert(sslReq.PublicKey, sslReq.PrivateKey)
-	if err != nil {
-		e := errno.FromMessage(errno.SslParseError, err.Error())
-		return e
-	}
-
-	ssl.ID = uuid.FromStringOrNil(id)
-	ssl.Status = 1
-	data := []byte(ssl.PublicKey)
-	hash := md5.Sum(data)
-	ssl.PublicKeyHash = fmt.Sprintf("%x", hash)
-
-	//check hash
-	exists := Ssl{}
-	conf.DB().Table("ssls").Where("public_key_hash = ?", ssl.PublicKeyHash).First(&exists)
-	if exists != (Ssl{}) {
-		e := errno.New(errno.DuplicateSslCert)
-		return e
-	}
-
-	//check sni
-	var snis []string
-	_ = json.Unmarshal([]byte(ssl.Snis), &snis)
-	sslReq.Snis = snis
-
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	// update mysql
-	if err := tx.Create(ssl).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBWriteError, err.Error())
-	}
-
-	//admin api
-
-	if _, err := sslReq.PutToApisix(id); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixSslCreateError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func SslUpdate(param interface{}, id string) error {
-	if id == "" {
-		return errno.New(errno.InvalidParam)
-	}
-
-	sslReq := &SslRequest{}
-	sslReq.Parse(param)
-
-	if sslReq.PrivateKey == "" {
-		return errno.New(errno.InvalidParamDetail, "Key is required")
-	}
-	if sslReq.PublicKey == "" {
-		return errno.New(errno.InvalidParamDetail, "Cert is required")
-	}
-
-	ssl, err := ParseCert(sslReq.PublicKey, sslReq.PrivateKey)
-	if err != nil {
-		return errno.FromMessage(errno.SslParseError, err.Error())
-	}
-
-	hash := md5.Sum([]byte(ssl.PublicKey))
-	ssl.ID = uuid.FromStringOrNil(id)
-	ssl.PublicKeyHash = fmt.Sprintf("%x", hash)
-
-	//check hash
-	exists := Ssl{}
-	conf.DB().Table("ssls").Where("public_key_hash = ?", ssl.PublicKeyHash).First(&exists)
-	if exists != (Ssl{}) && exists.ID != ssl.ID {
-		e := errno.New(errno.DuplicateSslCert)
-		return e
-	}
-
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	//sni check
-	var snis []string
-	_ = json.Unmarshal([]byte(ssl.Snis), &snis)
-	sslReq.Snis = snis
-
-	// update mysql
-	data := Ssl{PublicKey: ssl.PublicKey, Snis: ssl.Snis, ValidityStart: ssl.ValidityStart, ValidityEnd: ssl.ValidityEnd}
-	if err := tx.Model(&ssl).Updates(data).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBWriteError, err.Error())
-	}
-
-	//admin api
-	if _, err := sslReq.PutToApisix(id); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixSslUpdateError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func SslPatch(param interface{}, id string) error {
-	if id == "" {
-		return errno.New(errno.InvalidParam)
-	}
-
-	sslReq := &SslRequest{}
-	sslReq.Parse(param)
-
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	// update mysql
-	ssl := Ssl{}
-	ssl.ID = uuid.FromStringOrNil(id)
-	if err := tx.Model(&ssl).Update("status", sslReq.Status).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBWriteError, err.Error())
-	}
-
-	if _, err := sslReq.PatchToApisix(id); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixSslUpdateError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func SslDelete(id string) error {
-	if id == "" {
-		return errno.New(errno.InvalidParam)
-	}
-
-	// trans
-	tx := conf.DB().Begin()
-	defer func() {
-		if r := recover(); r != nil {
-			tx.Rollback()
-		}
-	}()
-
-	// delete from mysql
-	ssl := &Ssl{}
-	ssl.ID = uuid.FromStringOrNil(id)
-	if err := conf.DB().Delete(ssl).Error; err != nil {
-		tx.Rollback()
-		return errno.New(errno.DBDeleteError, err.Error())
-	}
-
-	// delete from apisix
-	request := &SslRequest{}
-	request.ID = id
-	if _, err := request.DeleteFromApisix(); err != nil {
-		tx.Rollback()
-		if _, ok := err.(*errno.HttpError); ok {
-			return err
-		}
-		e := errno.New(errno.ApisixSslDeleteError, err.Error())
-		return e
-	}
-
-	tx.Commit()
-
-	return nil
-}
-
-func (req *SslRequest) PatchToApisix(id string) (*ApisixSslResponse, error) {
-	url := fmt.Sprintf("%s/ssl/%s", conf.BaseUrl, id)
-	if data, err := json.Marshal(req); err != nil {
-		return nil, err
-	} else {
-		if resp, err := utils.Patch(url, data); err != nil {
-			logger.Error(url)
-			logger.Error(string(data))
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixSslResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error())
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (req *SslRequest) PutToApisix(rid string) (*ApisixSslResponse, error) {
-	url := fmt.Sprintf("%s/ssl/%s", conf.BaseUrl, rid)
-	if data, err := json.Marshal(req); err != nil {
-		return nil, err
-	} else {
-		if resp, err := utils.Put(url, data); err != nil {
-			logger.Error(url)
-			logger.Error(string(data))
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixSslResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error())
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (req *SslRequest) DeleteFromApisix() (*ApisixSslResponse, error) {
-	id := req.ID
-	url := fmt.Sprintf("%s/ssl/%s", conf.BaseUrl, id)
-
-	if resp, err := utils.Delete(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp ApisixSslResponse
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return &arresp, nil
-		}
-	}
-}
-
-func ParseCert(crt, key string) (*Ssl, error) {
-	if crt == "" || key == "" {
-		return nil, errors.New("invalid certificate")
-	}
-
-	certDERBlock, _ := pem.Decode([]byte(crt))
-	if certDERBlock == nil {
-		return nil, errors.New("Certificate resolution failed")
-	}
-	// match
-	_, err := tls.X509KeyPair([]byte(crt), []byte(key))
-	if err != nil {
-		return nil, errors.New("key and cert don't match")
-	}
-
-	x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
-
-	if err != nil {
-		return nil, errors.New("Certificate resolution failed")
-	} else {
-		ssl := Ssl{}
-		//domain
-		snis := []byte{}
-		if x509Cert.DNSNames != nil && len(x509Cert.DNSNames) > 0 {
-			snis, _ = json.Marshal(x509Cert.DNSNames)
-		} else if x509Cert.IPAddresses != nil && len(x509Cert.IPAddresses) > 0 {
-			snis, _ = json.Marshal(x509Cert.IPAddresses)
-		} else {
-			tmp := []string{}
-
-			if x509Cert.Subject.Names != nil && len(x509Cert.Subject.Names) > 1 {
-
-				var attributeTypeNames = map[string]string{
-					"2.5.4.6":  "C",
-					"2.5.4.10": "O",
-					"2.5.4.11": "OU",
-					"2.5.4.3":  "CN",
-					"2.5.4.5":  "SERIALNUMBER",
-					"2.5.4.7":  "L",
-					"2.5.4.8":  "ST",
-					"2.5.4.9":  "STREET",
-					"2.5.4.17": "POSTALCODE",
-				}
-
-				for _, tv := range x509Cert.Subject.Names {
-					oidString := tv.Type.String()
-					typeName, ok := attributeTypeNames[oidString]
-					if ok && typeName == "CN" {
-						valueString := fmt.Sprint(tv.Value)
-						tmp = append(tmp, valueString)
-					}
-
-				}
-			}
-
-			if len(tmp) < 1 && x509Cert.Subject.CommonName != "" {
-				tmp = []string{x509Cert.Subject.CommonName}
-			}
-
-			snis, _ = json.Marshal(tmp)
-		}
-		ssl.Snis = string(snis)
-
-		ssl.ValidityStart = uint64(x509Cert.NotBefore.Unix())
-		ssl.ValidityEnd = uint64(x509Cert.NotAfter.Unix())
-		ssl.PublicKey = crt
-
-		return &ssl, nil
-	}
-}
-
-func CheckSniExists(param interface{}) error {
-	var hosts []string
-	if err := json.Unmarshal(param.([]byte), &hosts); err != nil {
-		return errno.FromMessage(errno.InvalidParam)
-	}
-
-	sslList := []Ssl{}
-	db := conf.DB().Table("ssls")
-	db = db.Where("`status` = ? ", 1)
-
-	condition := ""
-	args := []interface{}{}
-	first := true
-	for _, host := range hosts {
-		idx := strings.Index(host, "*")
-		keyword := strings.Replace(host, "*.", "", -1)
-		if idx == -1 {
-			if j := strings.Index(host, "."); j != -1 {
-				keyword = host[j:]
-				//just one `.`
-				if j := strings.Index(host[(j+1):], "."); j == -1 {
-					keyword = host
-				}
-			}
-		}
-		if first {
-			condition = condition + "`snis` like ?"
-		} else {
-			condition = condition + " or `snis` like ?"
-		}
-		first = false
-		args = append(args, "%"+keyword+"%")
-	}
-	db = db.Where(condition, args...)
-
-	if err := db.Find(&sslList).Error; err != nil {
-		return errno.FromMessage(errno.SslForSniNotExists, hosts[0])
-	}
-
-hre:
-	for _, host := range hosts {
-		for _, ssl := range sslList {
-			sslDto := SslDto{}
-			sslDto.Parse(&ssl)
-			for _, sni := range sslDto.Snis {
-				if sni == host {
-					continue hre
-				}
-				regx := strings.Replace(sni, ".", `\.`, -1)
-				regx = strings.Replace(regx, "*", `([^\.]+)`, -1)
-				regx = "^" + regx + "$"
-				if isOk, _ := regexp.MatchString(regx, host); isOk {
-					continue hre
-				}
-			}
-		}
-		return errno.FromMessage(errno.SslForSniNotExists, host)
-	}
-
-	return nil
-}
-
-func DeleteTestSslData() {
-	db := conf.DB().Table("ssls")
-	db.Where("snis LIKE ? OR (snis LIKE ? AND snis LIKE ? )", "%*.route.com%", "%r.com%", "%s.com%").Delete(Ssl{})
-}
diff --git a/api/service/upstream.go b/api/service/upstream.go
deleted file mode 100644
index 5b9d920..0000000
--- a/api/service/upstream.go
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * 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 service
-
-import (
-	"encoding/json"
-	"fmt"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/errno"
-	"github.com/apisix/manager-api/utils"
-	uuid "github.com/satori/go.uuid"
-)
-
-type UpstreamDao struct {
-	Base
-	Name            string `json:"name"`
-	Description     string `json:"description,omitempty"`
-	Nodes           string `json:"nodes"`
-	Content         string `json:"content"`
-	ContentAdminApi string `json:"content_admin_api"`
-}
-
-func (UpstreamDao) TableName() string {
-	return "upstreams"
-}
-
-type ApisixUpstreamRequest struct {
-	Id          string `json:"id"`
-	Name        string `json:"name"`
-	Description string `json:"desc"`
-	Upstream
-}
-
-func (u *ApisixUpstreamRequest) toJson() []byte {
-	res, _ := json.Marshal(&u)
-	return res
-}
-
-type UpstreamRequest struct {
-	Id          string `json:"id,omitempty"`
-	Name        string `json:"name"`
-	Description string `json:"description"`
-	Upstream
-}
-
-func (u *UpstreamRequest) toJson() []byte {
-	res, _ := json.Marshal(&u)
-	return res
-}
-
-func (r *UpstreamRequest) Parse(body interface{}) error {
-	if err := json.Unmarshal(body.([]byte), r); err != nil {
-		r = nil
-		return err
-	}
-	return nil
-}
-
-func (r *UpstreamRequest) Parse2Apisix() (*ApisixUpstreamRequest, error) {
-	aur := &ApisixUpstreamRequest{
-		Id:          r.Id,
-		Name:        r.Name,
-		Description: r.Description,
-		Upstream:    r.Upstream,
-	}
-	return aur, nil
-}
-
-type UpstreamResponse struct {
-	Base
-	Name        string `json:"name"`
-	Description string `json:"description,omitempty"`
-	Upstream
-}
-
-type UpstreamNameResponse struct {
-	ID   string `json:"id"`
-	Name string `json:"name"`
-}
-
-func (u *UpstreamDao) Parse2NameResponse() (*UpstreamNameResponse, error) {
-	// upstream
-	unr := &UpstreamNameResponse{
-		ID:   u.ID.String(),
-		Name: u.Name,
-	}
-	return unr, nil
-}
-
-func (u *UpstreamDao) Parse2Response() (*UpstreamResponse, error) {
-	// upstream
-	aur := &ApisixUpstreamResponse{}
-	if err := json.Unmarshal([]byte(u.ContentAdminApi), &aur); err != nil {
-		return nil, err
-	} else {
-		v := aur.UNode.UValue
-		result := &UpstreamResponse{
-			Name:        v.Name,
-			Description: v.Description,
-		}
-		result.Base = u.Base
-		result.Upstream = Upstream{
-			UType:           v.UType,
-			Timeout:         v.Timeout,
-			Nodes:           v.Nodes,
-			EnableWebsocket: v.EnableWebsocket,
-		}
-		return result, nil
-	}
-}
-
-type ApisixUpstreamResponse struct {
-	Action string `json:"action"`
-	UNode  *UNode `json:"node"`
-}
-
-type UNode struct {
-	UValue        UValue `json:"value"`
-	ModifiedIndex uint64 `json:"modifiedIndex"`
-}
-
-type UValue struct {
-	Id          string `json:"id"`
-	Name        string `json:"name"`
-	Description string `json:"desc,omitempty"`
-	Upstream
-}
-
-func (u *UValue) toJson() []byte {
-	res, _ := json.Marshal(&u)
-	return res
-}
-
-func (aur *ApisixUpstreamResponse) Parse2Request() (*UpstreamRequest, error) {
-	v := aur.UNode.UValue
-	result := &UpstreamRequest{
-		Id:          v.Id,
-		Name:        v.Name,
-		Description: v.Description,
-		Upstream:    v.Upstream,
-	}
-	return result, nil
-}
-
-func Trans2UpstreamDao(resp *ApisixUpstreamResponse, r *UpstreamRequest) (*UpstreamDao, *errno.ManagerError) {
-	ips := make([]string, 0)
-	nodes := r.Nodes
-	for k, _ := range nodes {
-		ips = append(ips, k)
-	}
-	if nb, err := json.Marshal(ips); err != nil {
-		e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-		logger.Warn(e.Msg)
-		return nil, e
-	} else {
-		u := &UpstreamDao{
-			Name:        r.Name,
-			Description: r.Description,
-			Nodes:       string(nb),
-		}
-		// id
-		u.ID = uuid.FromStringOrNil(r.Id)
-		// content
-		if content, err := json.Marshal(r); err != nil {
-			e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-			return nil, e
-		} else {
-			u.Content = string(content)
-		}
-		// content_admin_api
-		if resp != nil {
-			if respStr, err := json.Marshal(resp); err != nil {
-				e := errno.FromMessage(errno.DBUpstreamError, err.Error())
-				return nil, e
-			} else {
-				u.ContentAdminApi = string(respStr)
-			}
-		}
-		return u, nil
-	}
-}
-
-func (aur *ApisixUpstreamRequest) Create() (*ApisixUpstreamResponse, error) {
-	url := fmt.Sprintf("%s/upstreams/%s", conf.BaseUrl, aur.Id)
-	if b, err := json.Marshal(aur); err != nil {
-		return nil, err
-	} else {
-		fmt.Println(string(b))
-		if resp, err := utils.Put(url, b); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixUpstreamResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error())
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (aur *ApisixUpstreamRequest) Update() (*ApisixUpstreamResponse, error) {
-	url := fmt.Sprintf("%s/upstreams/%s", conf.BaseUrl, aur.Id)
-	if b, err := json.Marshal(aur); err != nil {
-		return nil, err
-	} else {
-		fmt.Println(string(b))
-		if resp, err := utils.Put(url, b); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			var arresp ApisixUpstreamResponse
-			if err := json.Unmarshal(resp, &arresp); err != nil {
-				logger.Error(err.Error())
-				return nil, err
-			} else {
-				return &arresp, nil
-			}
-		}
-	}
-}
-
-func (arr *ApisixUpstreamRequest) FindById() (*ApisixUpstreamResponse, error) {
-	url := fmt.Sprintf("%s/upstreams/%s", conf.BaseUrl, arr.Id)
-	if resp, err := utils.Get(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp ApisixUpstreamResponse
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return &arresp, nil
-		}
-	}
-}
-
-func (arr *ApisixUpstreamRequest) Delete() (*ApisixUpstreamResponse, error) {
-	url := fmt.Sprintf("%s/upstreams/%s", conf.BaseUrl, arr.Id)
-	if resp, err := utils.Delete(url); err != nil {
-		logger.Error(err.Error())
-		return nil, err
-	} else {
-		var arresp ApisixUpstreamResponse
-		if err := json.Unmarshal(resp, &arresp); err != nil {
-			logger.Error(err.Error())
-			return nil, err
-		} else {
-			return &arresp, nil
-		}
-	}
-}
diff --git a/api/utils/copy.go b/api/utils/copy.go
deleted file mode 100644
index 30f228a..0000000
--- a/api/utils/copy.go
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 utils
-
-func CopyMap(origin map[string]interface{}) map[string]interface{} {
-	result := make(map[string]interface{})
-	for k, v := range origin {
-		result[k] = v
-	}
-	return result
-}
-
-func CopyStrings(origin [][]string) [][]string {
-	result := make([][]string, 0)
-	for _, s := range origin {
-		result = append(result, s)
-	}
-	return result
-}
-
-func Set2Map(origin []string) map[string]int {
-	result := make(map[string]int)
-	for _, s := range origin {
-		result[s] = 1
-	}
-	return result
-}
diff --git a/api/utils/http.go b/api/utils/http.go
deleted file mode 100644
index bdc9590..0000000
--- a/api/utils/http.go
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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 utils
-
-import (
-	"fmt"
-	"net/http"
-	"time"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/log"
-	"gopkg.in/resty.v1"
-)
-
-const timeout = 3000
-
-var logger = log.GetLogger()
-
-func Get(url string) ([]byte, error) {
-	r := resty.New().
-		SetTimeout(time.Duration(timeout)*time.Millisecond).
-		R().
-		SetHeader("content-type", "application/json").
-		SetHeader("X-API-KEY", conf.ApiKey)
-	resp, err := r.Get(url)
-	if err != nil {
-		return nil, err
-	}
-	if resp.StatusCode() != http.StatusOK {
-		return nil, fmt.Errorf("status: %d, body: %s", resp.StatusCode(), resp.Body())
-	}
-	return resp.Body(), nil
-}
-
-func Post(url string, bytes []byte) ([]byte, error) {
-	r := resty.New().
-		SetTimeout(time.Duration(timeout)*time.Millisecond).
-		R().
-		SetHeader("content-type", "application/json").
-		SetHeader("X-API-KEY", conf.ApiKey)
-	r.SetBody(bytes)
-	resp, err := r.Post(url)
-	if err != nil {
-		return nil, err
-	}
-	if resp.StatusCode() != http.StatusOK && resp.StatusCode() != http.StatusCreated {
-		return nil, fmt.Errorf("status: %d, body: %s", resp.StatusCode(), resp.Body())
-	}
-	return resp.Body(), nil
-}
-
-func Put(url string, bytes []byte) ([]byte, error) {
-	r := resty.New().
-		SetTimeout(time.Duration(timeout)*time.Millisecond).
-		R().
-		SetHeader("content-type", "application/json").
-		SetHeader("X-API-KEY", conf.ApiKey)
-	r.SetBody(bytes)
-	resp, err := r.Put(url)
-	if err != nil {
-		return nil, err
-	}
-	if resp.StatusCode() != http.StatusOK && resp.StatusCode() != http.StatusCreated {
-		return nil, fmt.Errorf("status: %d, body: %s", resp.StatusCode(), resp.Body())
-	}
-	return resp.Body(), nil
-}
-
-func Patch(url string, bytes []byte) ([]byte, error) {
-	r := resty.New().
-		SetTimeout(time.Duration(timeout)*time.Millisecond).
-		R().
-		SetHeader("content-type", "application/json").
-		SetHeader("X-API-KEY", conf.ApiKey)
-	r.SetBody(bytes)
-	resp, err := r.Patch(url)
-	if err != nil {
-		return nil, err
-	}
-	if resp.StatusCode() != http.StatusOK {
-		return nil, fmt.Errorf("status: %d, body: %s", resp.StatusCode(), resp.Body())
-	}
-	return resp.Body(), nil
-}
-
-func Delete(url string) ([]byte, error) {
-	r := resty.New().
-		SetTimeout(time.Duration(timeout)*time.Millisecond).
-		R().
-		SetHeader("content-type", "application/json").
-		SetHeader("X-API-KEY", conf.ApiKey)
-	resp, err := r.Delete(url)
-	if err != nil {
-		return nil, err
-	}
-	if resp.StatusCode() != http.StatusOK {
-		return nil, fmt.Errorf("status: %d, body: %s", resp.StatusCode(), resp.Body())
-	}
-	return resp.Body(), nil
-}