feat: simplify apisix client (#373)

diff --git a/pkg/apisix/cache/cache.go b/pkg/apisix/cache/cache.go
index 7cc9031..8ea26be 100644
--- a/pkg/apisix/cache/cache.go
+++ b/pkg/apisix/cache/cache.go
@@ -30,11 +30,11 @@
 	// InsertUpstream adds or updates upstream to cache.
 	InsertUpstream(*v1.Upstream) error
 
-	// GetRoute finds the route from cache according to the primary index.
+	// GetRoute finds the route from cache according to the primary index (id).
 	GetRoute(string) (*v1.Route, error)
-	// GetSSL finds the ssl from cache according to the primary index.
+	// GetSSL finds the ssl from cache according to the primary index (id).
 	GetSSL(string) (*v1.Ssl, error)
-	// GetUpstream finds the upstream from cache according to the primary index.
+	// GetUpstream finds the upstream from cache according to the primary index (id).
 	GetUpstream(string) (*v1.Upstream, error)
 
 	// ListRoutes lists all routes in cache.
diff --git a/pkg/apisix/cache/memdb.go b/pkg/apisix/cache/memdb.go
index f610a6d..b488e54 100644
--- a/pkg/apisix/cache/memdb.go
+++ b/pkg/apisix/cache/memdb.go
@@ -68,34 +68,34 @@
 	return nil
 }
 
-func (c *dbCache) GetRoute(key string) (*v1.Route, error) {
-	obj, err := c.get("route", key)
+func (c *dbCache) GetRoute(id string) (*v1.Route, error) {
+	obj, err := c.get("route", id)
 	if err != nil {
 		return nil, err
 	}
 	return obj.(*v1.Route).DeepCopy(), nil
 }
 
-func (c *dbCache) GetSSL(key string) (*v1.Ssl, error) {
-	obj, err := c.get("ssl", key)
+func (c *dbCache) GetSSL(id string) (*v1.Ssl, error) {
+	obj, err := c.get("ssl", id)
 	if err != nil {
 		return nil, err
 	}
 	return obj.(*v1.Ssl).DeepCopy(), nil
 }
 
-func (c *dbCache) GetUpstream(key string) (*v1.Upstream, error) {
-	obj, err := c.get("upstream", key)
+func (c *dbCache) GetUpstream(id string) (*v1.Upstream, error) {
+	obj, err := c.get("upstream", id)
 	if err != nil {
 		return nil, err
 	}
 	return obj.(*v1.Upstream).DeepCopy(), nil
 }
 
-func (c *dbCache) get(table, key string) (interface{}, error) {
+func (c *dbCache) get(table, id string) (interface{}, error) {
 	txn := c.db.Txn(false)
 	defer txn.Abort()
-	obj, err := txn.First(table, "id", key)
+	obj, err := txn.First(table, "id", id)
 	if err != nil {
 		if err == memdb.ErrNotFound {
 			return nil, ErrNotFound
diff --git a/pkg/apisix/cache/memdb_test.go b/pkg/apisix/cache/memdb_test.go
index 7bdd933..da820f2 100644
--- a/pkg/apisix/cache/memdb_test.go
+++ b/pkg/apisix/cache/memdb_test.go
@@ -29,32 +29,32 @@
 
 	r1 := &v1.Route{
 		Metadata: v1.Metadata{
-			FullName: "abc",
-			Name:     "abc",
+			ID:   "1",
+			Name: "abc",
 		},
 	}
 	assert.Nil(t, c.InsertRoute(r1), "inserting route 1")
 
-	r, err := c.GetRoute("abc")
+	r, err := c.GetRoute("1")
 	assert.Nil(t, err)
 	assert.Equal(t, r1, r)
 
 	r2 := &v1.Route{
 		Metadata: v1.Metadata{
-			FullName: "def",
-			Name:     "def",
+			ID:   "2",
+			Name: "def",
 		},
 	}
 	r3 := &v1.Route{
 		Metadata: v1.Metadata{
-			FullName: "ghi",
-			Name:     "ghi",
+			ID:   "3",
+			Name: "ghi",
 		},
 	}
 	assert.Nil(t, c.InsertRoute(r2), "inserting route r2")
 	assert.Nil(t, c.InsertRoute(r3), "inserting route r3")
 
-	r, err = c.GetRoute("ghi")
+	r, err = c.GetRoute("3")
 	assert.Nil(t, err)
 	assert.Equal(t, r3, r)
 
@@ -63,7 +63,7 @@
 	routes, err := c.ListRoutes()
 	assert.Nil(t, err, "listing routes")
 
-	if routes[0].FullName > routes[1].FullName {
+	if routes[0].Name > routes[1].Name {
 		routes[0], routes[1] = routes[1], routes[0]
 	}
 	assert.Equal(t, routes[0], r1)
@@ -71,8 +71,8 @@
 
 	r4 := &v1.Route{
 		Metadata: v1.Metadata{
-			FullName: "name4",
-			Name:     "name4",
+			ID:   "4",
+			Name: "name4",
 		},
 	}
 	assert.Error(t, ErrNotFound, c.DeleteRoute(r4))
@@ -83,8 +83,7 @@
 	assert.Nil(t, err, "NewMemDBCache")
 
 	s1 := &v1.Ssl{
-		ID:       "abc",
-		FullName: "abc",
+		ID: "abc",
 	}
 	assert.Nil(t, c.InsertSSL(s1), "inserting ssl 1")
 
@@ -93,12 +92,10 @@
 	assert.Equal(t, s1, s)
 
 	s2 := &v1.Ssl{
-		ID:       "def",
-		FullName: "def",
+		ID: "def",
 	}
 	s3 := &v1.Ssl{
-		ID:       "ghi",
-		FullName: "ghi",
+		ID: "ghi",
 	}
 	assert.Nil(t, c.InsertSSL(s2), "inserting ssl 2")
 	assert.Nil(t, c.InsertSSL(s3), "inserting ssl 3")
@@ -130,33 +127,33 @@
 
 	u1 := &v1.Upstream{
 		Metadata: v1.Metadata{
-			FullName: "abc",
-			Name:     "abc",
+			ID:   "1",
+			Name: "abc",
 		},
 	}
 	err = c.InsertUpstream(u1)
 	assert.Nil(t, err, "inserting upstream 1")
 
-	u, err := c.GetUpstream("abc")
+	u, err := c.GetUpstream("1")
 	assert.Nil(t, err)
 	assert.Equal(t, u1, u)
 
 	u2 := &v1.Upstream{
 		Metadata: v1.Metadata{
-			FullName: "def",
-			Name:     "def",
+			Name: "def",
+			ID:   "2",
 		},
 	}
 	u3 := &v1.Upstream{
 		Metadata: v1.Metadata{
-			FullName: "ghi",
-			Name:     "ghi",
+			Name: "ghi",
+			ID:   "3",
 		},
 	}
 	assert.Nil(t, c.InsertUpstream(u2), "inserting upstream 2")
 	assert.Nil(t, c.InsertUpstream(u3), "inserting upstream 3")
 
-	u, err = c.GetUpstream("ghi")
+	u, err = c.GetUpstream("3")
 	assert.Nil(t, err)
 	assert.Equal(t, u3, u)
 
@@ -165,7 +162,7 @@
 	upstreams, err := c.ListUpstreams()
 	assert.Nil(t, err, "listing upstreams")
 
-	if upstreams[0].FullName > upstreams[1].FullName {
+	if upstreams[0].Name > upstreams[1].Name {
 		upstreams[0], upstreams[1] = upstreams[1], upstreams[0]
 	}
 	assert.Equal(t, upstreams[0], u1)
@@ -173,8 +170,8 @@
 
 	u4 := &v1.Upstream{
 		Metadata: v1.Metadata{
-			FullName: "name4",
-			Name:     "name4",
+			Name: "name4",
+			ID:   "4",
 		},
 	}
 	assert.Error(t, ErrNotFound, c.DeleteUpstream(u4))
@@ -183,16 +180,15 @@
 func TestMemDBCacheReference(t *testing.T) {
 	r := &v1.Route{
 		Metadata: v1.Metadata{
-			FullName: "route",
-			Name:     "route",
+			Name: "route",
+			ID:   "1",
 		},
 		UpstreamId: "1",
 	}
 	u := &v1.Upstream{
 		Metadata: v1.Metadata{
-			ID:       "1",
-			FullName: "upstream",
-			Name:     "upstream",
+			ID:   "1",
+			Name: "upstream",
 		},
 	}
 
diff --git a/pkg/apisix/cache/schema.go b/pkg/apisix/cache/schema.go
index 159dcfc..40293f4 100644
--- a/pkg/apisix/cache/schema.go
+++ b/pkg/apisix/cache/schema.go
@@ -28,7 +28,7 @@
 					"id": {
 						Name:    "id",
 						Unique:  true,
-						Indexer: &memdb.StringFieldIndex{Field: "FullName"},
+						Indexer: &memdb.StringFieldIndex{Field: "ID"},
 					},
 					"name": {
 						Name:         "name",
@@ -50,7 +50,7 @@
 					"id": {
 						Name:    "id",
 						Unique:  true,
-						Indexer: &memdb.StringFieldIndex{Field: "FullName"},
+						Indexer: &memdb.StringFieldIndex{Field: "ID"},
 					},
 					"name": {
 						Name:         "name",
@@ -66,7 +66,7 @@
 					"id": {
 						Name:    "id",
 						Unique:  true,
-						Indexer: &memdb.StringFieldIndex{Field: "FullName"},
+						Indexer: &memdb.StringFieldIndex{Field: "ID"},
 					},
 				},
 			},
diff --git a/pkg/apisix/resource.go b/pkg/apisix/resource.go
index c2effe2..6be51fd 100644
--- a/pkg/apisix/resource.go
+++ b/pkg/apisix/resource.go
@@ -48,7 +48,7 @@
 
 type items []item
 
-// items implements json.Unmarshaler interface.
+// UnmarshalJSON implements json.Unmarshaler interface.
 // lua-cjson doesn't distinguish empty array and table,
 // and by default empty array will be encoded as '{}'.
 // We have to maintain the compatibility.
@@ -72,77 +72,34 @@
 	Value json.RawMessage `json:"value"`
 }
 
-type routeItem struct {
-	UpstreamId  string                 `json:"upstream_id"`
-	RemoteAddrs []string               `json:"remote_addrs"`
-	Host        string                 `json:"host"`
-	Hosts       []string               `json:"hosts"`
-	URI         string                 `json:"uri"`
-	Vars        [][]v1.StringOrSlice   `json:"vars"`
-	Uris        []string               `json:"uris"`
-	Desc        string                 `json:"desc"`
-	Methods     []string               `json:"methods"`
-	Priority    int                    `json:"priority"`
-	Plugins     map[string]interface{} `json:"plugins"`
-}
-
 // route decodes item.Value and converts it to v1.Route.
-func (i *item) route(clusterName string) (*v1.Route, error) {
+func (i *item) route() (*v1.Route, error) {
 	log.Debugf("got route: %s", string(i.Value))
 	list := strings.Split(i.Key, "/")
 	if len(list) < 1 {
 		return nil, fmt.Errorf("bad route config key: %s", i.Key)
 	}
 
-	var route routeItem
+	var route v1.Route
 	if err := json.Unmarshal(i.Value, &route); err != nil {
 		return nil, err
 	}
-
-	fullName := genFullName(route.Desc, clusterName)
-
-	return &v1.Route{
-		Metadata: v1.Metadata{
-			ID:       list[len(list)-1],
-			FullName: fullName,
-			Group:    clusterName,
-			Name:     route.Desc,
-		},
-		Host:        route.Host,
-		Path:        route.URI,
-		Uris:        route.Uris,
-		Vars:        route.Vars,
-		Methods:     route.Methods,
-		RemoteAddrs: route.RemoteAddrs,
-		UpstreamId:  route.UpstreamId,
-		Plugins:     route.Plugins,
-		Hosts:       route.Hosts,
-		Priority:    route.Priority,
-	}, nil
+	return &route, nil
 }
 
 // upstream decodes item.Value and converts it to v1.Upstream.
-func (i *item) upstream(clusterName string) (*v1.Upstream, error) {
+func (i *item) upstream() (*v1.Upstream, error) {
 	log.Debugf("got upstream: %s", string(i.Value))
 	list := strings.Split(i.Key, "/")
 	if len(list) < 1 {
 		return nil, fmt.Errorf("bad upstream config key: %s", i.Key)
 	}
 
-	var ups upstreamItem
+	var ups v1.Upstream
 	if err := json.Unmarshal(i.Value, &ups); err != nil {
 		return nil, err
 	}
 
-	var nodes []v1.UpstreamNode
-	for _, node := range ups.Nodes {
-		nodes = append(nodes, v1.UpstreamNode{
-			IP:     node.Host,
-			Port:   node.Port,
-			Weight: node.Weight,
-		})
-	}
-
 	// This is a work around scheme to avoid APISIX's
 	// health check schema about the health checker intervals.
 	if ups.Checks != nil && ups.Checks.Active != nil {
@@ -153,47 +110,15 @@
 			ups.Checks.Active.Healthy.Interval = int(v1.ActiveHealthCheckMinInterval.Seconds())
 		}
 	}
-
-	fullName := genFullName(ups.Desc, clusterName)
-
-	return &v1.Upstream{
-		Metadata: v1.Metadata{
-			ID:       list[len(list)-1],
-			FullName: fullName,
-			Group:    clusterName,
-			Name:     ups.Desc,
-		},
-		Type:    ups.LBType,
-		Key:     ups.Key,
-		HashOn:  ups.HashOn,
-		Nodes:   nodes,
-		Scheme:  ups.Scheme,
-		Checks:  ups.Checks,
-		Retries: ups.Retries,
-		Timeout: ups.Timeout,
-	}, nil
+	return &ups, nil
 }
 
 // ssl decodes item.Value and converts it to v1.Ssl.
-func (i *item) ssl(clusterName string) (*v1.Ssl, error) {
+func (i *item) ssl() (*v1.Ssl, error) {
 	log.Debugf("got ssl: %s", string(i.Value))
 	var ssl v1.Ssl
 	if err := json.Unmarshal(i.Value, &ssl); err != nil {
 		return nil, err
 	}
-
-	list := strings.Split(i.Key, "/")
-	id := list[len(list)-1]
-	ssl.ID = id
-	ssl.Group = clusterName
-	ssl.FullName = id
 	return &ssl, nil
 }
-
-func genFullName(name string, clusterName string) string {
-	fullName := name
-	if clusterName != "" {
-		fullName = clusterName + "_" + fullName
-	}
-	return fullName
-}
diff --git a/pkg/apisix/resource_test.go b/pkg/apisix/resource_test.go
index 0d08750..51ea1eb 100644
--- a/pkg/apisix/resource_test.go
+++ b/pkg/apisix/resource_test.go
@@ -59,19 +59,18 @@
 				"upstream_id": "13",
 				"host": "foo.com",
 				"uri": "/shop/133/details",
-				"desc": "unknown",
+				"name": "unknown",
 				"methods": ["GET", "POST"]
 			}
 		`),
 	}
 
-	r, err := item.route("qa")
+	r, err := item.route()
 	assert.Nil(t, err)
 	assert.Equal(t, r.UpstreamId, "13")
 	assert.Equal(t, r.Host, "foo.com")
-	assert.Equal(t, r.Path, "/shop/133/details")
+	assert.Equal(t, r.Uri, "/shop/133/details")
 	assert.Equal(t, r.Methods[0], "GET")
 	assert.Equal(t, r.Methods[1], "POST")
 	assert.Equal(t, r.Name, "unknown")
-	assert.Equal(t, r.FullName, "qa_unknown")
 }
diff --git a/pkg/apisix/route.go b/pkg/apisix/route.go
index ca238f7..21561c1 100644
--- a/pkg/apisix/route.go
+++ b/pkg/apisix/route.go
@@ -28,80 +28,66 @@
 	v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
-type routeReqBody struct {
-	Desc        string               `json:"desc,omitempty"`
-	Name        string               `json:"name,omitempty"`
-	URI         string               `json:"uri,omitempty"`
-	Priority    int                  `json:"priority,omitempty"`
-	Uris        []string             `json:"uris,omitempty"`
-	Vars        [][]v1.StringOrSlice `json:"vars,omitempty"`
-	Host        string               `json:"host,omitempty"`
-	Hosts       []string             `json:"hosts,omitempty"`
-	RemoteAddrs []string             `json:"remote_addrs,omitempty"`
-	UpstreamId  string               `json:"upstream_id,omitempty"`
-	Plugins     v1.Plugins           `json:"plugins,omitempty"`
-}
-
 type routeClient struct {
-	clusterName string
-	url         string
-	cluster     *cluster
+	url     string
+	cluster *cluster
 }
 
 func newRouteClient(c *cluster) Route {
 	return &routeClient{
-		clusterName: c.name,
-		url:         c.baseURL + "/routes",
-		cluster:     c,
+		url:     c.baseURL + "/routes",
+		cluster: c,
 	}
 }
 
+// Get returns the Route.
 // FIXME, currently if caller pass a non-existent resource, the Get always passes
 // through cache.
-func (r *routeClient) Get(ctx context.Context, fullname string) (*v1.Route, error) {
+func (r *routeClient) Get(ctx context.Context, name string) (*v1.Route, error) {
 	log.Debugw("try to look up route",
-		zap.String("fullname", fullname),
+		zap.String("name", name),
 		zap.String("url", r.url),
-		zap.String("cluster", r.clusterName),
+		zap.String("cluster", "default"),
 	)
-	route, err := r.cluster.cache.GetRoute(fullname)
+	rid := id.GenID(name)
+	route, err := r.cluster.cache.GetRoute(rid)
 	if err == nil {
 		return route, nil
 	}
 	if err != cache.ErrNotFound {
 		log.Errorw("failed to find route in cache, will try to lookup from APISIX",
-			zap.String("fullname", fullname),
+			zap.String("name", name),
 			zap.Error(err),
 		)
 	} else {
 		log.Debugw("failed to find route in cache, will try to lookup from APISIX",
-			zap.String("fullname", fullname),
+			zap.String("name", name),
 			zap.Error(err),
 		)
 	}
 
 	// TODO Add mutex here to avoid dog-pile effection.
-	url := r.url + "/" + id.GenID(fullname)
+	url := r.url + "/" + rid
 	resp, err := r.cluster.getResource(ctx, url)
 	if err != nil {
 		if err == cache.ErrNotFound {
 			log.Warnw("route not found",
-				zap.String("fullname", fullname),
+				zap.String("name", name),
 				zap.String("url", url),
-				zap.String("cluster", r.clusterName),
+				zap.String("cluster", "default"),
 			)
 		} else {
 			log.Errorw("failed to get route from APISIX",
-				zap.String("fullname", fullname),
+				zap.String("name", name),
 				zap.String("url", url),
-				zap.String("cluster", r.clusterName),
+				zap.String("cluster", "default"),
 				zap.Error(err),
 			)
 		}
 		return nil, err
 	}
 
-	route, err = resp.Item.route(r.clusterName)
+	route, err = resp.Item.route()
 	if err != nil {
 		log.Errorw("failed to convert route item",
 			zap.String("url", r.url),
@@ -122,7 +108,7 @@
 // to APISIX.
 func (r *routeClient) List(ctx context.Context) ([]*v1.Route, error) {
 	log.Debugw("try to list routes in APISIX",
-		zap.String("cluster", r.clusterName),
+		zap.String("cluster", "default"),
 		zap.String("url", r.url),
 	)
 	routeItems, err := r.cluster.listResource(ctx, r.url)
@@ -133,7 +119,7 @@
 
 	var items []*v1.Route
 	for i, item := range routeItems.Node.Items {
-		route, err := item.route(r.clusterName)
+		route, err := item.route()
 		if err != nil {
 			log.Errorw("failed to convert route item",
 				zap.String("url", r.url),
@@ -153,27 +139,15 @@
 func (r *routeClient) Create(ctx context.Context, obj *v1.Route) (*v1.Route, error) {
 	log.Debugw("try to create route",
 		zap.String("host", obj.Host),
-		zap.String("fullname", obj.FullName),
-		zap.String("cluster", r.clusterName),
+		zap.String("name", obj.Name),
+		zap.String("cluster", "default"),
 		zap.String("url", r.url),
 	)
 
 	if err := r.cluster.HasSynced(ctx); err != nil {
 		return nil, err
 	}
-	data, err := json.Marshal(routeReqBody{
-		Priority:    obj.Priority,
-		Desc:        obj.Name,
-		Name:        obj.Name,
-		URI:         obj.Path,
-		Host:        obj.Host,
-		Hosts:       obj.Hosts,
-		UpstreamId:  obj.UpstreamId,
-		Uris:        obj.Uris,
-		Plugins:     obj.Plugins,
-		Vars:        obj.Vars,
-		RemoteAddrs: obj.RemoteAddrs,
-	})
+	data, err := json.Marshal(obj)
 	if err != nil {
 		return nil, err
 	}
@@ -186,11 +160,7 @@
 		return nil, err
 	}
 
-	var clusterName string
-	if obj.Group != "" {
-		clusterName = obj.Group
-	}
-	route, err := resp.Item.route(clusterName)
+	route, err := resp.Item.route()
 	if err != nil {
 		return nil, err
 	}
@@ -204,8 +174,8 @@
 func (r *routeClient) Delete(ctx context.Context, obj *v1.Route) error {
 	log.Debugw("try to delete route",
 		zap.String("id", obj.ID),
-		zap.String("fullname", obj.FullName),
-		zap.String("cluster", r.clusterName),
+		zap.String("name", obj.Name),
+		zap.String("cluster", "default"),
 		zap.String("url", r.url),
 	)
 	if err := r.cluster.HasSynced(ctx); err != nil {
@@ -225,27 +195,15 @@
 func (r *routeClient) Update(ctx context.Context, obj *v1.Route) (*v1.Route, error) {
 	log.Debugw("try to update route",
 		zap.String("id", obj.ID),
-		zap.String("fullname", obj.FullName),
-		zap.String("cluster", r.clusterName),
+		zap.String("name", obj.Name),
+		zap.String("cluster", "default"),
 		zap.String("url", r.url),
 	)
 	if err := r.cluster.HasSynced(ctx); err != nil {
 		return nil, err
 	}
 	// FIXME use unified v1.Route, removing routeReqBody.
-	body, err := json.Marshal(routeReqBody{
-		Priority:    obj.Priority,
-		Desc:        obj.Name,
-		Name:        obj.Name,
-		URI:         obj.Path,
-		Host:        obj.Host,
-		Hosts:       obj.Hosts,
-		UpstreamId:  obj.UpstreamId,
-		Uris:        obj.Uris,
-		Plugins:     obj.Plugins,
-		Vars:        obj.Vars,
-		RemoteAddrs: obj.RemoteAddrs,
-	})
+	body, err := json.Marshal(obj)
 	if err != nil {
 		return nil, err
 	}
@@ -255,11 +213,7 @@
 	if err != nil {
 		return nil, err
 	}
-	var clusterName string
-	if obj.Group != "" {
-		clusterName = obj.Group
-	}
-	route, err := resp.Item.route(clusterName)
+	route, err := resp.Item.route()
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/apisix/route_test.go b/pkg/apisix/route_test.go
index 1624e1a..9aef459 100644
--- a/pkg/apisix/route_test.go
+++ b/pkg/apisix/route_test.go
@@ -181,12 +181,11 @@
 	// Create
 	obj, err := cli.Create(context.Background(), &v1.Route{
 		Metadata: v1.Metadata{
-			ID:       "1",
-			Name:     "test",
-			FullName: "test",
+			ID:   "1",
+			Name: "test",
 		},
 		Host:       "www.foo.com",
-		Path:       "/bar",
+		Uri:        "/bar",
 		UpstreamId: "1",
 	})
 	assert.Nil(t, err)
@@ -194,12 +193,11 @@
 
 	obj, err = cli.Create(context.Background(), &v1.Route{
 		Metadata: v1.Metadata{
-			ID:       "2",
-			Name:     "test",
-			FullName: "test",
+			ID:   "2",
+			Name: "test",
 		},
 		Host:       "www.foo.com",
-		Path:       "/bar",
+		Uri:        "/bar",
 		UpstreamId: "1",
 	})
 	assert.Nil(t, err)
@@ -222,12 +220,11 @@
 	// Patch then List
 	_, err = cli.Update(context.Background(), &v1.Route{
 		Metadata: v1.Metadata{
-			ID:       "2",
-			Name:     "test",
-			FullName: "test",
+			ID:   "2",
+			Name: "test",
 		},
 		Host:       "www.foo.com",
-		Path:       "/bar",
+		Uri:        "/bar",
 		UpstreamId: "112",
 	})
 	assert.Nil(t, err)
diff --git a/pkg/apisix/ssl.go b/pkg/apisix/ssl.go
index 7069c48..a860842 100644
--- a/pkg/apisix/ssl.go
+++ b/pkg/apisix/ssl.go
@@ -29,63 +29,61 @@
 )
 
 type sslClient struct {
-	url         string
-	clusterName string
-	cluster     *cluster
+	url     string
+	cluster *cluster
 }
 
 func newSSLClient(c *cluster) SSL {
 	return &sslClient{
-		url:         c.baseURL + "/ssl",
-		cluster:     c,
-		clusterName: c.name,
+		url:     c.baseURL + "/ssl",
+		cluster: c,
 	}
 }
 
-func (s *sslClient) Get(ctx context.Context, fullname string) (*v1.Ssl, error) {
+func (s *sslClient) Get(ctx context.Context, name string) (*v1.Ssl, error) {
 	log.Debugw("try to look up ssl",
-		zap.String("fullname", fullname),
+		zap.String("name", name),
 		zap.String("url", s.url),
-		zap.String("cluster", s.clusterName),
+		zap.String("cluster", "default"),
 	)
-
-	ssl, err := s.cluster.cache.GetSSL(fullname)
+	sid := id.GenID(name)
+	ssl, err := s.cluster.cache.GetSSL(sid)
 	if err == nil {
 		return ssl, nil
 	}
 	if err != cache.ErrNotFound {
 		log.Errorw("failed to find ssl in cache, will try to lookup from APISIX",
-			zap.String("fullname", fullname),
+			zap.String("name", name),
 			zap.Error(err),
 		)
 	} else {
 		log.Debugw("failed to find ssl in cache, will try to lookup from APISIX",
-			zap.String("fullname", fullname),
+			zap.String("name", name),
 			zap.Error(err),
 		)
 	}
 
 	// TODO Add mutex here to avoid dog-pile effection.
-	url := s.url + "/" + id.GenID(fullname)
+	url := s.url + "/" + sid
 	resp, err := s.cluster.getResource(ctx, url)
 	if err != nil {
 		if err == cache.ErrNotFound {
 			log.Warnw("ssl not found",
-				zap.String("fullname", fullname),
+				zap.String("name", name),
 				zap.String("url", url),
-				zap.String("cluster", s.clusterName),
+				zap.String("cluster", "default"),
 			)
 		} else {
 			log.Errorw("failed to get ssl from APISIX",
-				zap.String("fullname", fullname),
+				zap.String("name", name),
 				zap.String("url", url),
-				zap.String("cluster", s.clusterName),
+				zap.String("cluster", "default"),
 				zap.Error(err),
 			)
 		}
 		return nil, err
 	}
-	ssl, err = resp.Item.ssl(s.clusterName)
+	ssl, err = resp.Item.ssl()
 	if err != nil {
 		log.Errorw("failed to convert ssl item",
 			zap.String("url", s.url),
@@ -107,7 +105,7 @@
 func (s *sslClient) List(ctx context.Context) ([]*v1.Ssl, error) {
 	log.Debugw("try to list ssl in APISIX",
 		zap.String("url", s.url),
-		zap.String("cluster", s.clusterName),
+		zap.String("cluster", "default"),
 	)
 
 	sslItems, err := s.cluster.listResource(ctx, s.url)
@@ -118,7 +116,7 @@
 
 	var items []*v1.Ssl
 	for i, item := range sslItems.Node.Items {
-		ssl, err := item.ssl(s.clusterName)
+		ssl, err := item.ssl()
 		if err != nil {
 			log.Errorw("failed to convert ssl item",
 				zap.String("url", s.url),
@@ -136,7 +134,7 @@
 
 func (s *sslClient) Create(ctx context.Context, obj *v1.Ssl) (*v1.Ssl, error) {
 	log.Debugw("try to create ssl",
-		zap.String("cluster", s.clusterName),
+		zap.String("cluster", "default"),
 		zap.String("url", s.url),
 		zap.String("id", obj.ID),
 	)
@@ -161,12 +159,7 @@
 		return nil, err
 	}
 
-	var clusterName string
-	if obj.Group != "" {
-		clusterName = obj.Group
-	}
-
-	ssl, err := resp.Item.ssl(clusterName)
+	ssl, err := resp.Item.ssl()
 	if err != nil {
 		return nil, err
 	}
@@ -180,8 +173,7 @@
 func (s *sslClient) Delete(ctx context.Context, obj *v1.Ssl) error {
 	log.Debugw("try to delete ssl",
 		zap.String("id", obj.ID),
-		zap.String("cluster", s.clusterName),
-		zap.String("fullName", obj.FullName),
+		zap.String("cluster", "default"),
 		zap.String("url", s.url),
 	)
 	if err := s.cluster.HasSynced(ctx); err != nil {
@@ -201,20 +193,14 @@
 func (s *sslClient) Update(ctx context.Context, obj *v1.Ssl) (*v1.Ssl, error) {
 	log.Debugw("try to update ssl",
 		zap.String("id", obj.ID),
-		zap.String("cluster", s.clusterName),
+		zap.String("cluster", "default"),
 		zap.String("url", s.url),
 	)
 	if err := s.cluster.HasSynced(ctx); err != nil {
 		return nil, err
 	}
 	url := s.url + "/" + obj.ID
-	data, err := json.Marshal(v1.Ssl{
-		ID:     obj.ID,
-		Snis:   obj.Snis,
-		Cert:   obj.Cert,
-		Key:    obj.Key,
-		Status: obj.Status,
-	})
+	data, err := json.Marshal(obj)
 	if err != nil {
 		return nil, err
 	}
@@ -223,11 +209,7 @@
 	if err != nil {
 		return nil, err
 	}
-	var clusterName string
-	if obj.Group != "" {
-		clusterName = obj.Group
-	}
-	ssl, err := resp.Item.ssl(clusterName)
+	ssl, err := resp.Item.ssl()
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/apisix/ssl_test.go b/pkg/apisix/ssl_test.go
index 4717143..4f8585c 100644
--- a/pkg/apisix/ssl_test.go
+++ b/pkg/apisix/ssl_test.go
@@ -158,17 +158,15 @@
 
 	// Create
 	obj, err := cli.Create(context.TODO(), &v1.Ssl{
-		ID:    "1",
-		Group: "default",
-		Snis:  []string{"bar.com"},
+		ID:   "1",
+		Snis: []string{"bar.com"},
 	})
 	assert.Nil(t, err)
 	assert.Equal(t, obj.ID, "1")
 
 	obj, err = cli.Create(context.TODO(), &v1.Ssl{
-		ID:    "2",
-		Group: "default",
-		Snis:  []string{"bar.com"},
+		ID:   "2",
+		Snis: []string{"bar.com"},
 	})
 	assert.Nil(t, err)
 	assert.Equal(t, obj.ID, "2")
diff --git a/pkg/apisix/upstream.go b/pkg/apisix/upstream.go
index 94c5178..06e634b 100644
--- a/pkg/apisix/upstream.go
+++ b/pkg/apisix/upstream.go
@@ -18,7 +18,6 @@
 	"bytes"
 	"context"
 	"encoding/json"
-	"errors"
 
 	"go.uber.org/zap"
 
@@ -29,105 +28,62 @@
 )
 
 type upstreamClient struct {
-	clusterName string
-	url         string
-	cluster     *cluster
+	url     string
+	cluster *cluster
 }
 
-type upstreamNode struct {
-	Host   string `json:"host,omitempty" yaml:"ip,omitempty"`
-	Port   int    `json:"port,omitempty" yaml:"port,omitempty"`
-	Weight int    `json:"weight,omitempty" yaml:"weight,omitempty"`
-}
-
-type upstreamNodes []upstreamNode
-
-// items implements json.Unmarshaler interface.
-// lua-cjson doesn't distinguish empty array and table,
-// and by default empty array will be encoded as '{}'.
-// We have to maintain the compatibility.
-func (n *upstreamNodes) UnmarshalJSON(p []byte) error {
-	if p[0] == '{' {
-		if len(p) != 2 {
-			return errors.New("unexpected non-empty object")
-		}
-		return nil
-	}
-	var data []upstreamNode
-	if err := json.Unmarshal(p, &data); err != nil {
-		return err
-	}
-	*n = data
-	return nil
-}
-
-type upstreamReqBody struct {
-	LBType  string                  `json:"type"`
-	HashOn  string                  `json:"hash_on,omitempty"`
-	Key     string                  `json:"key,omitempty"`
-	Nodes   upstreamNodes           `json:"nodes"`
-	Desc    string                  `json:"desc"`
-	Name    string                  `json:"name"`
-	Scheme  string                  `json:"scheme,omitempty"`
-	Retries int                     `json:"retries,omitempty"`
-	Timeout *v1.UpstreamTimeout     `json:"timeout,omitempty"`
-	Checks  *v1.UpstreamHealthCheck `json:"checks,omitempty"`
-}
-
-type upstreamItem upstreamReqBody
-
 func newUpstreamClient(c *cluster) Upstream {
 	return &upstreamClient{
-		url:         c.baseURL + "/upstreams",
-		cluster:     c,
-		clusterName: c.name,
+		url:     c.baseURL + "/upstreams",
+		cluster: c,
 	}
 }
 
-func (u *upstreamClient) Get(ctx context.Context, fullname string) (*v1.Upstream, error) {
+func (u *upstreamClient) Get(ctx context.Context, name string) (*v1.Upstream, error) {
 	log.Debugw("try to look up upstream",
-		zap.String("fullname", fullname),
+		zap.String("name", name),
 		zap.String("url", u.url),
-		zap.String("cluster", u.clusterName),
+		zap.String("cluster", "default"),
 	)
-	ups, err := u.cluster.cache.GetUpstream(fullname)
+	uid := id.GenID(name)
+	ups, err := u.cluster.cache.GetUpstream(uid)
 	if err == nil {
 		return ups, nil
 	}
 	if err != cache.ErrNotFound {
 		log.Errorw("failed to find upstream in cache, will try to lookup from APISIX",
-			zap.String("fullname", fullname),
+			zap.String("name", name),
 			zap.Error(err),
 		)
 	} else {
 		log.Debugw("failed to find upstream in cache, will try to lookup from APISIX",
-			zap.String("fullname", fullname),
+			zap.String("name", name),
 			zap.Error(err),
 		)
 	}
 
 	// TODO Add mutex here to avoid dog-pile effection.
-	url := u.url + "/" + id.GenID(fullname)
+	url := u.url + "/" + uid
 	resp, err := u.cluster.getResource(ctx, url)
 	if err != nil {
 		if err == cache.ErrNotFound {
 			log.Warnw("upstream not found",
-				zap.String("fullname", fullname),
+				zap.String("name", name),
 				zap.String("url", url),
-				zap.String("cluster", u.clusterName),
+				zap.String("cluster", "default"),
 			)
 		} else {
 			log.Errorw("failed to get upstream from APISIX",
-				zap.String("fullname", fullname),
+				zap.String("name", name),
 				zap.String("url", url),
-				zap.String("cluster", u.clusterName),
+				zap.String("cluster", "default"),
 				zap.Error(err),
 			)
 		}
 		return nil, err
 	}
 
-	ups, err = resp.Item.upstream(u.clusterName)
+	ups, err = resp.Item.upstream()
 	if err != nil {
 		log.Errorw("failed to convert upstream item",
 			zap.String("url", u.url),
@@ -149,7 +105,7 @@
 func (u *upstreamClient) List(ctx context.Context) ([]*v1.Upstream, error) {
 	log.Debugw("try to list upstreams in APISIX",
 		zap.String("url", u.url),
-		zap.String("cluster", u.clusterName),
+		zap.String("cluster", "default"),
 	)
 
 	upsItems, err := u.cluster.listResource(ctx, u.url)
@@ -160,7 +116,7 @@
 
 	var items []*v1.Upstream
 	for i, item := range upsItems.Node.Items {
-		ups, err := item.upstream(u.clusterName)
+		ups, err := item.upstream()
 		if err != nil {
 			log.Errorw("failed to convert upstream item",
 				zap.String("url", u.url),
@@ -177,35 +133,16 @@
 
 func (u *upstreamClient) Create(ctx context.Context, obj *v1.Upstream) (*v1.Upstream, error) {
 	log.Debugw("try to create upstream",
-		zap.String("fullname", obj.FullName),
+		zap.String("name", obj.Name),
 		zap.String("url", u.url),
-		zap.String("cluster", u.clusterName),
+		zap.String("cluster", "default"),
 	)
 
 	if err := u.cluster.HasSynced(ctx); err != nil {
 		return nil, err
 	}
 
-	nodes := make(upstreamNodes, 0, len(obj.Nodes))
-	for _, node := range obj.Nodes {
-		nodes = append(nodes, upstreamNode{
-			Host:   node.IP,
-			Port:   node.Port,
-			Weight: node.Weight,
-		})
-	}
-	body, err := json.Marshal(upstreamReqBody{
-		LBType:  obj.Type,
-		HashOn:  obj.HashOn,
-		Key:     obj.Key,
-		Nodes:   nodes,
-		Desc:    obj.Name,
-		Name:    obj.Name,
-		Scheme:  obj.Scheme,
-		Checks:  obj.Checks,
-		Retries: obj.Retries,
-		Timeout: obj.Timeout,
-	})
+	body, err := json.Marshal(obj)
 	if err != nil {
 		return nil, err
 	}
@@ -217,11 +154,7 @@
 		log.Errorf("failed to create upstream: %s", err)
 		return nil, err
 	}
-	var clusterName string
-	if obj.Group != "" {
-		clusterName = obj.Group
-	}
-	ups, err := resp.Item.upstream(clusterName)
+	ups, err := resp.Item.upstream()
 	if err != nil {
 		return nil, err
 	}
@@ -235,8 +168,8 @@
 func (u *upstreamClient) Delete(ctx context.Context, obj *v1.Upstream) error {
 	log.Debugw("try to delete upstream",
 		zap.String("id", obj.ID),
-		zap.String("fullname", obj.FullName),
-		zap.String("cluster", u.clusterName),
+		zap.String("name", obj.Name),
+		zap.String("cluster", "default"),
 		zap.String("url", u.url),
 	)
 
@@ -257,8 +190,8 @@
 func (u *upstreamClient) Update(ctx context.Context, obj *v1.Upstream) (*v1.Upstream, error) {
 	log.Debugw("try to update upstream",
 		zap.String("id", obj.ID),
-		zap.String("fullname", obj.FullName),
-		zap.String("cluster", u.clusterName),
+		zap.String("name", obj.Name),
+		zap.String("cluster", "default"),
 		zap.String("url", u.url),
 	)
 
@@ -266,26 +199,7 @@
 		return nil, err
 	}
 
-	nodes := make(upstreamNodes, 0, len(obj.Nodes))
-	for _, node := range obj.Nodes {
-		nodes = append(nodes, upstreamNode{
-			Host:   node.IP,
-			Port:   node.Port,
-			Weight: node.Weight,
-		})
-	}
-	body, err := json.Marshal(upstreamReqBody{
-		LBType:  obj.Type,
-		HashOn:  obj.HashOn,
-		Key:     obj.Key,
-		Nodes:   nodes,
-		Desc:    obj.Name,
-		Name:    obj.Name,
-		Scheme:  obj.Scheme,
-		Checks:  obj.Checks,
-		Retries: obj.Retries,
-		Timeout: obj.Timeout,
-	})
+	body, err := json.Marshal(obj)
 	if err != nil {
 		return nil, err
 	}
@@ -296,11 +210,7 @@
 	if err != nil {
 		return nil, err
 	}
-	var clusterName string
-	if obj.Group != "" {
-		clusterName = obj.Group
-	}
-	ups, err := resp.Item.upstream(clusterName)
+	ups, err := resp.Item.upstream()
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/apisix/upstream_test.go b/pkg/apisix/upstream_test.go
index 9fa7045..13ef65b 100644
--- a/pkg/apisix/upstream_test.go
+++ b/pkg/apisix/upstream_test.go
@@ -159,15 +159,13 @@
 	// Create
 	key := "upstream/abc"
 	lbType := "roundrobin"
-	fullName := "default_test"
-	group := "default"
 	name := "test"
 	ip := "10.0.11.153"
 	port := 15006
 	weight := 100
-	nodes := []v1.UpstreamNode{
+	nodes := v1.UpstreamNodes{
 		{
-			IP:     ip,
+			Host:   ip,
 			Port:   port,
 			Weight: weight,
 		},
@@ -175,10 +173,8 @@
 
 	obj, err := cli.Create(context.TODO(), &v1.Upstream{
 		Metadata: v1.Metadata{
-			ID:       "1",
-			FullName: fullName,
-			Group:    group,
-			Name:     name,
+			ID:   "1",
+			Name: name,
 		},
 		Type:  lbType,
 		Key:   key,
@@ -190,10 +186,8 @@
 	id2 := "2"
 	obj, err = cli.Create(context.TODO(), &v1.Upstream{
 		Metadata: v1.Metadata{
-			ID:       id2,
-			FullName: fullName,
-			Group:    group,
-			Name:     name,
+			ID:   id2,
+			Name: name,
 		},
 		Type:  lbType,
 		Key:   key,
@@ -219,10 +213,8 @@
 	// Patch then List
 	_, err = cli.Update(context.Background(), &v1.Upstream{
 		Metadata: v1.Metadata{
-			ID:       "2",
-			FullName: fullName,
-			Group:    group,
-			Name:     name,
+			ID:   "2",
+			Name: name,
 		},
 		Type:  "chash",
 		Key:   key,
diff --git a/pkg/ingress/endpoint.go b/pkg/ingress/endpoint.go
index f839150..42c2e63 100644
--- a/pkg/ingress/endpoint.go
+++ b/pkg/ingress/endpoint.go
@@ -128,7 +128,7 @@
 	return nil
 }
 
-func (c *endpointsController) syncToCluster(ctx context.Context, cluster apisix.Cluster, nodes []apisixv1.UpstreamNode, upsName string) error {
+func (c *endpointsController) syncToCluster(ctx context.Context, cluster apisix.Cluster, nodes apisixv1.UpstreamNodes, upsName string) error {
 	upstream, err := cluster.Upstream().Get(ctx, upsName)
 	if err != nil {
 		if err == apisixcache.ErrNotFound {
diff --git a/pkg/ingress/types.go b/pkg/ingress/types.go
deleted file mode 100644
index 640ba00..0000000
--- a/pkg/ingress/types.go
+++ /dev/null
@@ -1,22 +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 ingress
-
-const (
-	ADD           = "ADD"
-	UPDATE        = "UPDATE"
-	DELETE        = "DELETE"
-	WatchFromKind = "watch"
-)
diff --git a/pkg/kube/translation/apisix_route.go b/pkg/kube/translation/apisix_route.go
index 4cfc37a..dd8917c 100644
--- a/pkg/kube/translation/apisix_route.go
+++ b/pkg/kube/translation/apisix_route.go
@@ -62,16 +62,13 @@
 			upsId := id.GenID(upstreamName)
 			route := &apisixv1.Route{
 				Metadata: apisixv1.Metadata{
-					ID:              id.GenID(routeName),
-					FullName:        routeName,
-					ResourceVersion: ar.ResourceVersion,
-					Name:            routeName,
+					ID:   id.GenID(routeName),
+					Name: routeName,
 				},
-				Host:         r.Host,
-				Path:         p.Path,
-				UpstreamName: upstreamName,
-				UpstreamId:   upsId,
-				Plugins:      pluginMap,
+				Host:       r.Host,
+				Uri:        p.Path,
+				UpstreamId: upsId,
+				Plugins:    pluginMap,
 			}
 			routes = append(routes, route)
 
@@ -80,11 +77,9 @@
 				if err != nil {
 					return nil, nil, err
 				}
-				ups.FullName = upstreamName
 				ups.ID = upsId
-				ups.ResourceVersion = ar.ResourceVersion
 				ups.Name = upstreamName
-				upstreamMap[ups.FullName] = ups
+				upstreamMap[ups.Name] = ups
 			}
 		}
 	}
@@ -179,20 +174,17 @@
 		upsId := id.GenID(upstreamName)
 		route := &apisixv1.Route{
 			Metadata: apisixv1.Metadata{
-				FullName:        routeName,
-				Name:            routeName,
-				ID:              id.GenID(routeName),
-				ResourceVersion: ar.ResourceVersion,
+				Name: routeName,
+				ID:   id.GenID(routeName),
 			},
-			Priority:     part.Priority,
-			RemoteAddrs:  part.Match.RemoteAddrs,
-			Vars:         exprs,
-			Hosts:        part.Match.Hosts,
-			Uris:         part.Match.Paths,
-			Methods:      part.Match.Methods,
-			UpstreamName: upstreamName,
-			UpstreamId:   upsId,
-			Plugins:      pluginMap,
+			Priority:    part.Priority,
+			RemoteAddrs: part.Match.RemoteAddrs,
+			Vars:        exprs,
+			Hosts:       part.Match.Hosts,
+			Uris:        part.Match.Paths,
+			Methods:     part.Match.Methods,
+			UpstreamId:  upsId,
+			Plugins:     pluginMap,
 		}
 
 		if len(backends) > 0 {
@@ -209,8 +201,8 @@
 				return nil, nil, err
 			}
 			for _, u := range ups {
-				if _, ok := upstreamMap[u.FullName]; !ok {
-					upstreamMap[u.FullName] = u
+				if _, ok := upstreamMap[u.Name]; !ok {
+					upstreamMap[u.Name] = u
 				}
 			}
 			route.Plugins["traffic-split"] = plugin
@@ -222,7 +214,7 @@
 			if err != nil {
 				return nil, nil, err
 			}
-			upstreamMap[ups.FullName] = ups
+			upstreamMap[ups.Name] = ups
 		}
 	}
 
diff --git a/pkg/kube/translation/apisix_ssl.go b/pkg/kube/translation/apisix_ssl.go
index 9572b3b..51f4de8 100644
--- a/pkg/kube/translation/apisix_ssl.go
+++ b/pkg/kube/translation/apisix_ssl.go
@@ -45,14 +45,12 @@
 	}
 	var snis []string
 	snis = append(snis, tls.Spec.Hosts...)
-	fullname := tls.Namespace + "_" + tls.Name
 	ssl := &apisix.Ssl{
-		ID:       id.GenID(fullname),
-		FullName: fullname,
-		Snis:     snis,
-		Cert:     string(cert),
-		Key:      string(key),
-		Status:   1,
+		ID:     id.GenID(tls.Namespace + "_" + tls.Name),
+		Snis:   snis,
+		Cert:   string(cert),
+		Key:    string(key),
+		Status: 1,
 	}
 	return ssl, nil
 }
diff --git a/pkg/kube/translation/ingress.go b/pkg/kube/translation/ingress.go
index ca80370..d1e3f8e 100644
--- a/pkg/kube/translation/ingress.go
+++ b/pkg/kube/translation/ingress.go
@@ -73,13 +73,12 @@
 			}
 			route := &apisixv1.Route{
 				Metadata: apisixv1.Metadata{
-					FullName: composeIngressRouteName(rule.Host, pathRule.Path),
+					Name: composeIngressRouteName(rule.Host, pathRule.Path),
 				},
 				Host: rule.Host,
 				Uris: uris,
 			}
-			route.ID = id.GenID(route.FullName)
-			route.Name = route.FullName
+			route.ID = id.GenID(route.Name)
 			if ups != nil {
 				route.UpstreamId = ups.ID
 			}
@@ -133,13 +132,12 @@
 			}
 			route := &apisixv1.Route{
 				Metadata: apisixv1.Metadata{
-					FullName: composeIngressRouteName(rule.Host, pathRule.Path),
+					Name: composeIngressRouteName(rule.Host, pathRule.Path),
 				},
 				Host: rule.Host,
 				Uris: uris,
 			}
-			route.Name = route.FullName
-			route.ID = id.GenID(route.FullName)
+			route.ID = id.GenID(route.Name)
 			if ups != nil {
 				route.UpstreamId = ups.ID
 			}
@@ -175,9 +173,8 @@
 	if err != nil {
 		return nil, err
 	}
-	ups.FullName = apisixv1.ComposeUpstreamName(namespace, backend.Name, svcPort)
-	ups.Name = ups.FullName
-	ups.ID = id.GenID(ups.FullName)
+	ups.Name = apisixv1.ComposeUpstreamName(namespace, backend.Name, svcPort)
+	ups.ID = id.GenID(ups.Name)
 	return ups, nil
 }
 
@@ -226,13 +223,12 @@
 			}
 			route := &apisixv1.Route{
 				Metadata: apisixv1.Metadata{
-					FullName: composeIngressRouteName(rule.Host, pathRule.Path),
+					Name: composeIngressRouteName(rule.Host, pathRule.Path),
 				},
 				Host: rule.Host,
 				Uris: uris,
 			}
-			route.Name = route.FullName
-			route.ID = id.GenID(route.FullName)
+			route.ID = id.GenID(route.Name)
 			if ups != nil {
 				route.UpstreamId = ups.ID
 			}
@@ -268,9 +264,8 @@
 	if err != nil {
 		return nil, err
 	}
-	ups.FullName = apisixv1.ComposeUpstreamName(namespace, svcName, portNumber)
-	ups.Name = ups.FullName
-	ups.ID = id.GenID(ups.FullName)
+	ups.Name = apisixv1.ComposeUpstreamName(namespace, svcName, portNumber)
+	ups.ID = id.GenID(ups.Name)
 	return ups, nil
 }
 
diff --git a/pkg/kube/translation/ingress_test.go b/pkg/kube/translation/ingress_test.go
index ecf3226..b6d44c5 100644
--- a/pkg/kube/translation/ingress_test.go
+++ b/pkg/kube/translation/ingress_test.go
@@ -302,17 +302,17 @@
 	assert.Equal(t, upstreams[0].Scheme, "http")
 	assert.Len(t, upstreams[0].Nodes, 2)
 	assert.Equal(t, upstreams[0].Nodes[0].Port, 9080)
-	assert.Equal(t, upstreams[0].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, upstreams[0].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, upstreams[0].Nodes[1].Port, 9080)
-	assert.Equal(t, upstreams[0].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, upstreams[0].Nodes[1].Host, "192.168.1.2")
 
 	assert.Equal(t, upstreams[1].Type, "roundrobin")
 	assert.Equal(t, upstreams[1].Scheme, "http")
 	assert.Len(t, upstreams[1].Nodes, 2)
 	assert.Equal(t, upstreams[1].Nodes[0].Port, 9443)
-	assert.Equal(t, upstreams[1].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, upstreams[1].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, upstreams[1].Nodes[1].Port, 9443)
-	assert.Equal(t, upstreams[1].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, upstreams[1].Nodes[1].Host, "192.168.1.2")
 }
 
 func TestTranslateIngressV1beta1NoBackend(t *testing.T) {
@@ -525,17 +525,17 @@
 	assert.Equal(t, upstreams[0].Scheme, "http")
 	assert.Len(t, upstreams[0].Nodes, 2)
 	assert.Equal(t, upstreams[0].Nodes[0].Port, 9080)
-	assert.Equal(t, upstreams[0].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, upstreams[0].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, upstreams[0].Nodes[1].Port, 9080)
-	assert.Equal(t, upstreams[0].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, upstreams[0].Nodes[1].Host, "192.168.1.2")
 
 	assert.Equal(t, upstreams[1].Type, "roundrobin")
 	assert.Equal(t, upstreams[1].Scheme, "http")
 	assert.Len(t, upstreams[1].Nodes, 2)
 	assert.Equal(t, upstreams[1].Nodes[0].Port, 9443)
-	assert.Equal(t, upstreams[1].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, upstreams[1].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, upstreams[1].Nodes[1].Port, 9443)
-	assert.Equal(t, upstreams[1].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, upstreams[1].Nodes[1].Host, "192.168.1.2")
 }
 
 func TestTranslateIngressExtensionsV1beta1(t *testing.T) {
@@ -638,17 +638,17 @@
 	assert.Equal(t, upstreams[0].Scheme, "http")
 	assert.Len(t, upstreams[0].Nodes, 2)
 	assert.Equal(t, upstreams[0].Nodes[0].Port, 9080)
-	assert.Equal(t, upstreams[0].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, upstreams[0].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, upstreams[0].Nodes[1].Port, 9080)
-	assert.Equal(t, upstreams[0].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, upstreams[0].Nodes[1].Host, "192.168.1.2")
 
 	assert.Equal(t, upstreams[1].Type, "roundrobin")
 	assert.Equal(t, upstreams[1].Scheme, "http")
 	assert.Len(t, upstreams[1].Nodes, 2)
 	assert.Equal(t, upstreams[1].Nodes[0].Port, 9443)
-	assert.Equal(t, upstreams[1].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, upstreams[1].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, upstreams[1].Nodes[1].Port, 9443)
-	assert.Equal(t, upstreams[1].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, upstreams[1].Nodes[1].Host, "192.168.1.2")
 }
 
 func TestTranslateIngressExtensionsV1beta1BackendWithInvalidService(t *testing.T) {
diff --git a/pkg/kube/translation/plugin_test.go b/pkg/kube/translation/plugin_test.go
index 28916fe..e8ab921 100644
--- a/pkg/kube/translation/plugin_test.go
+++ b/pkg/kube/translation/plugin_test.go
@@ -180,16 +180,16 @@
 	assert.Nil(t, err)
 
 	assert.Len(t, ups, 2)
-	assert.Equal(t, ups[0].FullName, "test_svc-1_80")
+	assert.Equal(t, ups[0].Name, "test_svc-1_80")
 	assert.Len(t, ups[0].Nodes, 2)
-	assert.Equal(t, ups[0].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, ups[0].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, ups[0].Nodes[0].Port, 9080)
-	assert.Equal(t, ups[0].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, ups[0].Nodes[1].Host, "192.168.1.2")
 	assert.Equal(t, ups[0].Nodes[1].Port, 9080)
 
-	assert.Equal(t, ups[1].FullName, "test_svc-1_443")
+	assert.Equal(t, ups[1].Name, "test_svc-1_443")
 	assert.Len(t, ups[1].Nodes, 1)
-	assert.Equal(t, ups[1].Nodes[0].IP, "10.0.5.3")
+	assert.Equal(t, ups[1].Nodes[0].Host, "10.0.5.3")
 	assert.Equal(t, ups[1].Nodes[0].Port, 443)
 
 	assert.Len(t, cfg.Rules, 1)
@@ -351,18 +351,18 @@
 	// Here ups has two elements, but the duplicated one will be
 	// removed in TranslateApisixRouteV2alpha1.
 	assert.Len(t, ups, 2)
-	assert.Equal(t, ups[0].FullName, "test_svc-1_80")
+	assert.Equal(t, ups[0].Name, "test_svc-1_80")
 	assert.Len(t, ups[0].Nodes, 2)
-	assert.Equal(t, ups[0].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, ups[0].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, ups[0].Nodes[0].Port, 9080)
-	assert.Equal(t, ups[0].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, ups[0].Nodes[1].Host, "192.168.1.2")
 	assert.Equal(t, ups[0].Nodes[1].Port, 9080)
 
-	assert.Equal(t, ups[1].FullName, "test_svc-1_80")
+	assert.Equal(t, ups[1].Name, "test_svc-1_80")
 	assert.Len(t, ups[1].Nodes, 2)
-	assert.Equal(t, ups[1].Nodes[0].IP, "192.168.1.1")
+	assert.Equal(t, ups[1].Nodes[0].Host, "192.168.1.1")
 	assert.Equal(t, ups[1].Nodes[0].Port, 9080)
-	assert.Equal(t, ups[1].Nodes[1].IP, "192.168.1.2")
+	assert.Equal(t, ups[1].Nodes[1].Host, "192.168.1.2")
 	assert.Equal(t, ups[1].Nodes[1].Port, 9080)
 
 	assert.Len(t, cfg.Rules, 1)
diff --git a/pkg/kube/translation/translator.go b/pkg/kube/translation/translator.go
index 705bf35..4a6765a 100644
--- a/pkg/kube/translation/translator.go
+++ b/pkg/kube/translation/translator.go
@@ -45,7 +45,7 @@
 type Translator interface {
 	// TranslateUpstreamNodes translate Endpoints resources to APISIX Upstream nodes
 	// according to the give port.
-	TranslateUpstreamNodes(*corev1.Endpoints, int32) ([]apisixv1.UpstreamNode, error)
+	TranslateUpstreamNodes(*corev1.Endpoints, int32) (apisixv1.UpstreamNodes, error)
 	// TranslateUpstreamConfig translates ApisixUpstreamConfig (part of ApisixUpstream)
 	// to APISIX Upstream, it doesn't fill the the Upstream metadata and nodes.
 	TranslateUpstreamConfig(*configv1.ApisixUpstreamConfig) (*apisixv1.Upstream, error)
@@ -144,7 +144,7 @@
 	return ups, nil
 }
 
-func (t *translator) TranslateUpstreamNodes(endpoints *corev1.Endpoints, port int32) ([]apisixv1.UpstreamNode, error) {
+func (t *translator) TranslateUpstreamNodes(endpoints *corev1.Endpoints, port int32) (apisixv1.UpstreamNodes, error) {
 	svc, err := t.ServiceLister.Services(endpoints.Namespace).Get(endpoints.Name)
 	if err != nil {
 		return nil, &translateError{
@@ -166,7 +166,9 @@
 			reason: "port not defined",
 		}
 	}
-	var nodes []apisixv1.UpstreamNode
+	// As nodes is not optional, here we create an empty slice,
+	// not a nil slice.
+	nodes := make(apisixv1.UpstreamNodes, 0)
 	for _, subset := range endpoints.Subsets {
 		var epPort *corev1.EndpointPort
 		for _, port := range subset.Ports {
@@ -178,7 +180,7 @@
 		if epPort != nil {
 			for _, addr := range subset.Addresses {
 				nodes = append(nodes, apisixv1.UpstreamNode{
-					IP:   addr.IP,
+					Host: addr.IP,
 					Port: int(epPort.Port),
 					// FIXME Custom node weight
 					Weight: _defaultWeight,
diff --git a/pkg/kube/translation/translator_test.go b/pkg/kube/translation/translator_test.go
index 51bc1c8..e056130 100644
--- a/pkg/kube/translation/translator_test.go
+++ b/pkg/kube/translation/translator_test.go
@@ -184,14 +184,14 @@
 
 	nodes, err = tr.TranslateUpstreamNodes(endpoints, 80)
 	assert.Nil(t, err)
-	assert.Equal(t, nodes, []apisixv1.UpstreamNode{
+	assert.Equal(t, nodes, apisixv1.UpstreamNodes{
 		{
-			IP:     "192.168.1.1",
+			Host:   "192.168.1.1",
 			Port:   9080,
 			Weight: 100,
 		},
 		{
-			IP:     "192.168.1.2",
+			Host:   "192.168.1.2",
 			Port:   9080,
 			Weight: 100,
 		},
@@ -199,14 +199,14 @@
 
 	nodes, err = tr.TranslateUpstreamNodes(endpoints, 443)
 	assert.Nil(t, err)
-	assert.Equal(t, nodes, []apisixv1.UpstreamNode{
+	assert.Equal(t, nodes, apisixv1.UpstreamNodes{
 		{
-			IP:     "192.168.1.1",
+			Host:   "192.168.1.1",
 			Port:   9443,
 			Weight: 100,
 		},
 		{
-			IP:     "192.168.1.2",
+			Host:   "192.168.1.2",
 			Port:   9443,
 			Weight: 100,
 		},
diff --git a/pkg/kube/translation/util.go b/pkg/kube/translation/util.go
index a66b7dd..76af4d3 100644
--- a/pkg/kube/translation/util.go
+++ b/pkg/kube/translation/util.go
@@ -76,17 +76,16 @@
 		return nil, err
 	}
 	if svcResolveGranularity == "service" {
-		ups.Nodes = []apisixv1.UpstreamNode{
+		ups.Nodes = apisixv1.UpstreamNodes{
 			{
-				IP:     svcClusterIP,
+				Host:   svcClusterIP,
 				Port:   int(svcPort),
 				Weight: _defaultWeight,
 			},
 		}
 	}
-	ups.FullName = apisixv1.ComposeUpstreamName(namespace, svcName, svcPort)
-	ups.Name = ups.FullName
-	ups.ID = id.GenID(ups.FullName)
+	ups.Name = apisixv1.ComposeUpstreamName(namespace, svcName, svcPort)
+	ups.ID = id.GenID(ups.Name)
 	return ups, nil
 }
 
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index 5128ba8..4eec171 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -70,11 +70,8 @@
 
 // Metadata contains all meta information about resources.
 type Metadata struct {
-	ID              string `json:"id,omitempty" yaml:"id,omitempty"`
-	FullName        string `json:"full_name,omitempty" yaml:"full_name,omitempty"`
-	Name            string `json:"name,omitempty" yaml:"name,omitempty"`
-	ResourceVersion string `json:"resource_version,omitempty" yaml:"resource_version,omitempty"`
-	Group           string `json:"group,omitempty" yaml:"group,omitempty"`
+	ID   string `json:"id,omitempty" yaml:"id,omitempty"`
+	Name string `json:"name,omitempty" yaml:"name,omitempty"`
 }
 
 // Route apisix route object
@@ -82,19 +79,19 @@
 type Route struct {
 	Metadata `json:",inline" yaml:",inline"`
 
-	Host         string            `json:"host,omitempty" yaml:"host,omitempty"`
-	Hosts        []string          `json:"hosts,omitempty" yaml:"hosts,omitempty"`
-	Path         string            `json:"path,omitempty" yaml:"path,omitempty"`
-	Priority     int               `json:"priority,omitempty" yaml:"priority,omitempty"`
-	Vars         [][]StringOrSlice `json:"vars,omitempty" yaml:"vars,omitempty"`
-	Uris         []string          `json:"uris,omitempty" yaml:"uris,omitempty"`
-	Methods      []string          `json:"methods,omitempty" yaml:"methods,omitempty"`
-	RemoteAddrs  []string          `json:"remote_addrs,omitempty" yaml:"remote_addrs,omitempty"`
-	UpstreamId   string            `json:"upstream_id,omitempty" yaml:"upstream_id,omitempty"`
-	UpstreamName string            `json:"upstream_name,omitempty" yaml:"upstream_name,omitempty"`
-	Plugins      Plugins           `json:"plugins,omitempty" yaml:"plugins,omitempty"`
+	Host        string            `json:"host,omitempty" yaml:"host,omitempty"`
+	Hosts       []string          `json:"hosts,omitempty" yaml:"hosts,omitempty"`
+	Uri         string            `json:"uri,omitempty" yaml:"uri,omitempty"`
+	Priority    int               `json:"priority,omitempty" yaml:"priority,omitempty"`
+	Vars        [][]StringOrSlice `json:"vars,omitempty" yaml:"vars,omitempty"`
+	Uris        []string          `json:"uris,omitempty" yaml:"uris,omitempty"`
+	Methods     []string          `json:"methods,omitempty" yaml:"methods,omitempty"`
+	RemoteAddrs []string          `json:"remote_addrs,omitempty" yaml:"remote_addrs,omitempty"`
+	UpstreamId  string            `json:"upstream_id,omitempty" yaml:"upstream_id,omitempty"`
+	Plugins     Plugins           `json:"plugins,omitempty" yaml:"plugins,omitempty"`
 }
 
+// StringOrSlice represents a string or a string slice.
 // TODO Do not use interface{} to avoid the reflection overheads.
 // +k8s:deepcopy-gen=true
 type StringOrSlice struct {
@@ -154,7 +151,7 @@
 	HashOn  string               `json:"hash_on,omitempty" yaml:"hash_on,omitempty"`
 	Key     string               `json:"key,omitempty" yaml:"key,omitempty"`
 	Checks  *UpstreamHealthCheck `json:"checks,omitempty" yaml:"checks,omitempty"`
-	Nodes   []UpstreamNode       `json:"nodes,omitempty" yaml:"nodes,omitempty"`
+	Nodes   UpstreamNodes        `json:"nodes" yaml:"nodes"`
 	Scheme  string               `json:"scheme,omitempty" yaml:"scheme,omitempty"`
 	Retries int                  `json:"retries,omitempty" yaml:"retries,omitempty"`
 	Timeout *UpstreamTimeout     `json:"timeout,omitempty" yaml:"timeout,omitempty"`
@@ -170,10 +167,32 @@
 	Read int `json:"read" yaml:"read"`
 }
 
-// Node the node in upstream
+// UpstreamNodes is the upstream node list.
+type UpstreamNodes []UpstreamNode
+
+// UnmarshalJSON implements json.Unmarshaler interface.
+// lua-cjson doesn't distinguish empty array and table,
+// and by default empty array will be encoded as '{}'.
+// We have to maintain the compatibility.
+func (n *UpstreamNodes) UnmarshalJSON(p []byte) error {
+	if p[0] == '{' {
+		if len(p) != 2 {
+			return errors.New("unexpected non-empty object")
+		}
+		return nil
+	}
+	var data []UpstreamNode
+	if err := json.Unmarshal(p, &data); err != nil {
+		return err
+	}
+	*n = data
+	return nil
+}
+
+// UpstreamNode is the node in upstream
 // +k8s:deepcopy-gen=true
 type UpstreamNode struct {
-	IP     string `json:"ip,omitempty" yaml:"ip,omitempty"`
+	Host   string `json:"host,omitempty" yaml:"host,omitempty"`
 	Port   int    `json:"port,omitempty" yaml:"port,omitempty"`
 	Weight int    `json:"weight,omitempty" yaml:"weight,omitempty"`
 }
@@ -249,13 +268,11 @@
 // Ssl apisix ssl object
 // +k8s:deepcopy-gen=true
 type Ssl struct {
-	ID       string   `json:"id,omitempty" yaml:"id,omitempty"`
-	FullName string   `json:"full_name,omitempty" yaml:"full_name,omitempty"`
-	Snis     []string `json:"snis,omitempty" yaml:"snis,omitempty"`
-	Cert     string   `json:"cert,omitempty" yaml:"cert,omitempty"`
-	Key      string   `json:"key,omitempty" yaml:"key,omitempty"`
-	Status   int      `json:"status,omitempty" yaml:"status,omitempty"`
-	Group    string   `json:"group,omitempty" yaml:"group,omitempty"`
+	ID     string   `json:"id,omitempty" yaml:"id,omitempty"`
+	Snis   []string `json:"snis,omitempty" yaml:"snis,omitempty"`
+	Cert   string   `json:"cert,omitempty" yaml:"cert,omitempty"`
+	Key    string   `json:"key,omitempty" yaml:"key,omitempty"`
+	Status int      `json:"status,omitempty" yaml:"status,omitempty"`
 }
 
 // TrafficSplitConfig is the config of traffic-split plugin.
diff --git a/test/e2e/ingress/resourcepushing.go b/test/e2e/ingress/resourcepushing.go
index 54f64de..fd93d99 100644
--- a/test/e2e/ingress/resourcepushing.go
+++ b/test/e2e/ingress/resourcepushing.go
@@ -216,7 +216,7 @@
 
 		// Upstream doesn't change.
 		assert.Equal(ginkgo.GinkgoT(), newUpstreams[0].ID, upstreams[0].ID)
-		assert.Equal(ginkgo.GinkgoT(), newUpstreams[0].FullName, upstreams[0].FullName)
+		assert.Equal(ginkgo.GinkgoT(), newUpstreams[0].Name, upstreams[0].Name)
 
 		s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.com").Expect().
 			Status(http.StatusNotFound).