From a9bbe17047879cc7403cd7b40f418ab17313a582 Mon Sep 17 00:00:00 2001
From: Evstigneev Denis <danteevstigneev@yandex.ru>
Date: Thu, 27 Feb 2025 22:45:32 +0300
Subject: [PATCH 1/4] prepare v4

---
 go.mod                                 |  21 +--
 go.sum                                 |  26 ++--
 handler.go                             | 132 ++++++++++---------
 handler/generate.go                    |   6 +-
 handler/graphql/graphql.go             |   4 +-
 handler/health/health.go               |   4 +-
 handler/health/health.proto            |   4 +-
 handler/health/health_micro.pb.go      |  14 +-
 handler/health/health_micro_http.pb.go | 103 ++-------------
 handler/meter/meter.go                 |  15 ++-
 handler/meter/meter.proto              |   2 +-
 handler/meter/meter_micro.pb.go        |  11 +-
 handler/meter/meter_micro_http.pb.go   |  49 ++-----
 handler/swagger/swagger.go             |   2 +-
 http.go                                | 124 ++----------------
 message.go                             |   4 +-
 options.go                             |   2 +-
 request.go                             |   7 +-
 server.go                              |   4 +-
 subscriber.go                          | 175 -------------------------
 util.go                                |  39 +++---
 util_test.go                           |   6 +-
 22 files changed, 188 insertions(+), 566 deletions(-)
 delete mode 100644 subscriber.go

diff --git a/go.mod b/go.mod
index 381d1d7..8fccbcd 100644
--- a/go.mod
+++ b/go.mod
@@ -1,14 +1,12 @@
-module go.unistack.org/micro-server-http/v3
-
-go 1.22.0
+module go.unistack.org/micro-server-http/v4
 
+go 1.22.2
 
 require (
-	go.unistack.org/micro-client-http/v3 v3.9.15
 	go.unistack.org/micro-codec-yaml/v3 v3.10.3
-	go.unistack.org/micro-proto/v3 v3.4.1
-	go.unistack.org/micro/v3 v3.11.30
-	golang.org/x/net v0.33.0
+	go.unistack.org/micro-proto/v4 v4.1.0
+	go.unistack.org/micro/v4 v4.1.2
+	golang.org/x/net v0.34.0
 )
 
 require (
@@ -17,9 +15,12 @@ require (
 	github.com/google/gnostic-models v0.6.9 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/matoous/go-nanoid v1.5.1 // indirect
-	golang.org/x/sys v0.28.0 // indirect
+	github.com/spf13/cast v1.7.1 // indirect
+	go.unistack.org/micro-proto/v3 v3.4.1 // indirect
+	go.unistack.org/micro/v3 v3.11.30 // indirect
+	golang.org/x/sys v0.29.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
-	google.golang.org/grpc v1.69.2 // indirect
-	google.golang.org/protobuf v1.36.1 // indirect
+	google.golang.org/grpc v1.69.4 // indirect
+	google.golang.org/protobuf v1.36.3 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 7063604..6068486 100644
--- a/go.sum
+++ b/go.sum
@@ -657,6 +657,8 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+
 github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
 github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
 github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
@@ -837,6 +839,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
 github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
+github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
+github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -872,14 +876,16 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
-go.unistack.org/micro-client-http/v3 v3.9.15 h1:d2t/8P0FrvZwIpdqwHwn9+7rP5zcDa4DKXgBfTCZTeo=
-go.unistack.org/micro-client-http/v3 v3.9.15/go.mod h1:KS6qxpxGDQmcszBaJpidc1KOr528QflEKoGopl0qYJ8=
 go.unistack.org/micro-codec-yaml/v3 v3.10.3 h1:H0jM4wCSReHzEc1hnKYgXjzg171+tUE6IHxdxvgq/cQ=
 go.unistack.org/micro-codec-yaml/v3 v3.10.3/go.mod h1:pruYGvCULoHa6Tfah1UnTrwCzQhy0KT6D4UXEMgf+tk=
 go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q=
 go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
+go.unistack.org/micro-proto/v4 v4.1.0 h1:qPwL2n/oqh9RE3RTTDgt28XK3QzV597VugQPaw9lKUk=
+go.unistack.org/micro-proto/v4 v4.1.0/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec=
 go.unistack.org/micro/v3 v3.11.30 h1:XTLgZubSGzQL85IUMp1pTJnS1lP4eFwTZyelV/SzOMc=
 go.unistack.org/micro/v3 v3.11.30/go.mod h1:fvOkXKs3wKHToWH6Mxy+aovEiDl2q4UlOCdVfJdziBU=
+go.unistack.org/micro/v4 v4.1.2 h1:9SOlPYyPNNFpg1A7BsvhDyQm3gysLH1AhWbDCp1hyoY=
+go.unistack.org/micro/v4 v4.1.2/go.mod h1:lr3oYED8Ay1vjK68QqRw30QOtdk/ffpZqMFDasOUhKw=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -1001,8 +1007,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
-golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1122,8 +1128,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -1471,8 +1477,8 @@ google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
 google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
-google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
-google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
+google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
+google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1491,8 +1497,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
-google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
+google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/handler.go b/handler.go
index bfe601c..b96785f 100644
--- a/handler.go
+++ b/handler.go
@@ -12,16 +12,16 @@ import (
 	"sync"
 	"time"
 
-	"go.unistack.org/micro/v3/errors"
-	"go.unistack.org/micro/v3/logger"
-	"go.unistack.org/micro/v3/metadata"
-	"go.unistack.org/micro/v3/meter"
-	"go.unistack.org/micro/v3/options"
-	"go.unistack.org/micro/v3/semconv"
-	"go.unistack.org/micro/v3/server"
-	"go.unistack.org/micro/v3/tracer"
-	rhttp "go.unistack.org/micro/v3/util/http"
-	rflutil "go.unistack.org/micro/v3/util/reflect"
+	"go.unistack.org/micro/v4/errors"
+	"go.unistack.org/micro/v4/logger"
+	"go.unistack.org/micro/v4/metadata"
+	"go.unistack.org/micro/v4/meter"
+	"go.unistack.org/micro/v4/options"
+	"go.unistack.org/micro/v4/semconv"
+	"go.unistack.org/micro/v4/server"
+	"go.unistack.org/micro/v4/tracer"
+	rhttp "go.unistack.org/micro/v4/util/http"
+	rflutil "go.unistack.org/micro/v4/util/reflect"
 )
 
 var (
@@ -110,20 +110,21 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error)
 			md = metadata.New(len(r.Header) + 8)
 		}
 		for k, v := range r.Header {
-			md[k] = strings.Join(v, ", ")
+			md[k] = append(md[k], v...)
 		}
-		md["RemoteAddr"] = r.RemoteAddr
-		md["Method"] = r.Method
-		md["URL"] = r.URL.String()
-		md["Proto"] = r.Proto
-		md["Content-Length"] = fmt.Sprintf("%d", r.ContentLength)
-		md["Transfer-Encoding"] = strings.Join(r.TransferEncoding, ",")
-		md["Host"] = r.Host
-		md["RequestURI"] = r.RequestURI
+
+		md["RemoteAddr"] = append(md["RemoteAddr"], r.RemoteAddr)
+		md["Method"] = append(md["Method"], r.Method)
+		md["URL"] = append(md["URL"], r.URL.String())
+		md["Proto"] = append(md["Proto"], r.Proto)
+		md["Content-Length"] = append(md["Content-Length"], fmt.Sprintf("%d", r.ContentLength))
+		md["Transfer-Encoding"] = append(md["Transfer-Encoding"], r.TransferEncoding...)
+		md["Host"] = append(md["Host"], r.Host)
+		md["RequestURI"] = append(md["RequestURI"], r.RequestURI)
 		if r.TLS != nil {
-			md["TLS"] = "true"
-			md["TLS-ALPN"] = r.TLS.NegotiatedProtocol
-			md["TLS-ServerName"] = r.TLS.ServerName
+			md["TLS"] = append(md["TLS"], "true")
+			md["TLS-ALPN"] = append(md["TLS-ALPN"], r.TLS.NegotiatedProtocol)
+			md["TLS-ServerName"] = append(md["TLS-ServerName"], r.TLS.ServerName)
 		}
 
 		ctx = metadata.NewIncomingContext(ctx, md)
@@ -160,18 +161,20 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error)
 		if !match && h.registerRPC {
 			microMethod, mok := md.Get(metadata.HeaderEndpoint)
 			if mok {
-				serviceMethod := strings.Split(microMethod, ".")
-				if len(serviceMethod) == 2 {
-					if shdlr, ok := h.handlers[serviceMethod[0]]; ok {
-						hdlr := shdlr.(*httpHandler)
-						fh, mp, err := hdlr.handlers.Search(http.MethodPost, "/"+microMethod)
-						if err == nil {
-							// match = true
-							for k, v := range mp {
-								matches[k] = v
+				for i := range microMethod {
+					serviceMethod := strings.Split(microMethod[i], ".")
+					if len(serviceMethod) == 2 {
+						if shdlr, ok := h.handlers[serviceMethod[0]]; ok {
+							hdlr := shdlr.(*httpHandler)
+							fh, mp, err := hdlr.handlers.Search(http.MethodPost, "/"+microMethod[i])
+							if err == nil {
+								// match = true
+								for k, v := range mp {
+									matches[k] = v
+								}
+								hldr = fh.(*patHandler)
+								handler = hdlr
 							}
-							hldr = fh.(*patHandler)
-							handler = hdlr
 						}
 					}
 				}
@@ -263,10 +266,10 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error)
 			}
 			if nmd, ok := metadata.FromOutgoingContext(fctx); ok {
 				for k, v := range nmd {
-					md.Set(k, v)
+					md[k] = append(md[k], v...)
 				}
 			}
-			metadata.SetOutgoingContext(ctx, md)
+			ctx = metadata.NewOutgoingContext(ctx, md)
 
 			return err
 		}
@@ -293,7 +296,9 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error)
 		w.Header().Set(metadata.HeaderContentType, ct)
 		if md, ok := metadata.FromOutgoingContext(ctx); ok {
 			for k, v := range md {
-				w.Header().Set(k, v)
+				for i := range v {
+					w.Header().Set(k, v[i])
+				}
 			}
 		}
 		if md := getRspHeader(ctx); md != nil {
@@ -357,23 +362,24 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		md = metadata.New(len(r.Header) + 8)
 	}
 	for k, v := range r.Header {
-		md[k] = strings.Join(v, ", ")
+		md[k] = append(md[k], v...)
 	}
-	md["RemoteAddr"] = r.RemoteAddr
+
+	md["RemoteAddr"] = append(md["RemoteAddr"], r.RemoteAddr)
 	if r.TLS != nil {
-		md["Scheme"] = "https"
+		md["Scheme"] = append(md["Scheme"], "https")
 	} else {
-		md["Scheme"] = "http"
+		md["Scheme"] = append(md["Scheme"], "http")
 	}
-	md["Method"] = r.Method
-	md["URL"] = r.URL.String()
-	md["Proto"] = r.Proto
-	md["ContentLength"] = fmt.Sprintf("%d", r.ContentLength)
+	md["Method"] = append(md["Method"], r.Method)
+	md["URL"] = append(md["URL"], r.URL.String())
+	md["Proto"] = append(md["Proto"], r.Proto)
+	md["Content-Length"] = append(md["Content-Length"], fmt.Sprintf("%d", r.ContentLength))
 	if len(r.TransferEncoding) > 0 {
-		md["TransferEncoding"] = strings.Join(r.TransferEncoding, ",")
+		md["TransferEncoding"] = append(md["Content-Length"], r.TransferEncoding...)
 	}
-	md["Host"] = r.Host
-	md["RequestURI"] = r.RequestURI
+	md["Host"] = append(md["Host"], r.Host)
+	md["RequestURI"] = append(md["RequestURI"], r.RequestURI)
 	ctx = metadata.NewIncomingContext(ctx, md)
 	ctx = metadata.NewOutgoingContext(ctx, metadata.New(0))
 
@@ -409,18 +415,20 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	if !match && h.registerRPC {
 		microMethod, mok := md.Get(metadata.HeaderEndpoint)
 		if mok {
-			serviceMethod := strings.Split(microMethod, ".")
-			if len(serviceMethod) == 2 {
-				if shdlr, ok := h.handlers[serviceMethod[0]]; ok {
-					hdlr := shdlr.(*httpHandler)
-					fh, mp, err := hdlr.handlers.Search(http.MethodPost, "/"+microMethod)
-					if err == nil {
-						match = true
-						for k, v := range mp {
-							matches[k] = v
+			for i := range microMethod {
+				serviceMethod := strings.Split(microMethod[i], ".")
+				if len(serviceMethod) == 2 {
+					if shdlr, ok := h.handlers[serviceMethod[0]]; ok {
+						hdlr := shdlr.(*httpHandler)
+						fh, mp, err := hdlr.handlers.Search(http.MethodPost, "/"+microMethod[i])
+						if err == nil {
+							match = true
+							for k, v := range mp {
+								matches[k] = v
+							}
+							hldr = fh.(*patHandler)
+							handler = hdlr
 						}
-						hldr = fh.(*patHandler)
-						handler = hdlr
 					}
 				}
 			}
@@ -628,10 +636,10 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		}
 		if nmd, ok := metadata.FromOutgoingContext(fctx); ok {
 			for k, v := range nmd {
-				md.Set(k, v)
+				md[k] = append(md[k], v...)
 			}
 		}
-		metadata.SetOutgoingContext(ctx, md)
+		ctx = metadata.NewOutgoingContext(ctx, md)
 
 		if err != nil && sp != nil {
 			sp.SetStatus(tracer.SpanStatusError, err.Error())
@@ -661,7 +669,9 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set(metadata.HeaderContentType, ct)
 	if md, ok := metadata.FromOutgoingContext(ctx); ok {
 		for k, v := range md {
-			w.Header().Set(k, v)
+			for i := range v {
+				w.Header().Set(k, v[i])
+			}
 		}
 	}
 	if md := getRspHeader(ctx); md != nil {
diff --git a/handler/generate.go b/handler/generate.go
index 8f8c5ed..da07e43 100644
--- a/handler/generate.go
+++ b/handler/generate.go
@@ -2,11 +2,11 @@ package handler
 
 import (
 	// import required packages
-	_ "go.unistack.org/micro-proto/v3/openapiv3"
+	_ "go.unistack.org/micro-proto/v4/openapiv3"
 )
 
 //go:generate sh -c "curl -L https://github.com/swagger-api/swagger-ui/archive/refs/tags/v4.18.3.zip -o - | bsdtar -C swagger-ui --strip-components=2 -xv swagger-ui-4.18.3/dist && rm swagger-ui/*.map swagger-ui/*-es-*.js swagger-ui/swagger-ui.js swagger-ui/swagger-initializer.js"
 
-//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v3) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ ./meter/meter.proto"
+//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v4) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ ./meter/meter.proto"
 
-//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v3) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ ./health/health.proto"
+//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v4) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ ./health/health.proto"
diff --git a/handler/graphql/graphql.go b/handler/graphql/graphql.go
index 287fb57..7188509 100644
--- a/handler/graphql/graphql.go
+++ b/handler/graphql/graphql.go
@@ -7,8 +7,8 @@ import (
 	"fmt"
 
 	"github.com/99designs/gqlgen/graphql"
-	"go.unistack.org/micro/v3/logger"
-	"go.unistack.org/micro/v3/store"
+	"go.unistack.org/micro/v4/logger"
+	"go.unistack.org/micro/v4/store"
 )
 
 var _ graphql.Cache = (*cacheWrapper)(nil)
diff --git a/handler/health/health.go b/handler/health/health.go
index 9731a0d..51669dd 100644
--- a/handler/health/health.go
+++ b/handler/health/health.go
@@ -3,8 +3,8 @@ package health_handler
 import (
 	"context"
 
-	codecpb "go.unistack.org/micro-proto/v3/codec"
-	"go.unistack.org/micro/v3/errors"
+	codecpb "go.unistack.org/micro-proto/v4/codec"
+	"go.unistack.org/micro/v4/errors"
 )
 
 var _ HealthServiceServer = &Handler{}
diff --git a/handler/health/health.proto b/handler/health/health.proto
index 715e9b4..c42b8bd 100644
--- a/handler/health/health.proto
+++ b/handler/health/health.proto
@@ -1,7 +1,7 @@
 syntax = "proto3";
 
-package micro.server.http.v3.handler.health;
-option go_package = "go.unistack.org/micro-server-http/v3/handler/health;health_handler";
+package micro.server.http.v4.handler.health;
+option go_package = "go.unistack.org/micro-server-http/v4/handler/health;health_handler";
 
 import "api/annotations.proto";
 import "openapiv3/annotations.proto";
diff --git a/handler/health/health_micro.pb.go b/handler/health/health_micro.pb.go
index 37ad339..c226578 100644
--- a/handler/health/health_micro.pb.go
+++ b/handler/health/health_micro.pb.go
@@ -1,28 +1,20 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-micro v3.10.4
-// - protoc              v5.28.3
+// - protoc-gen-go-micro v4.0.2
+// - protoc              v3.21.12
 // source: health/health.proto
 
 package health_handler
 
 import (
 	context "context"
-	codec "go.unistack.org/micro-proto/v3/codec"
-	client "go.unistack.org/micro/v3/client"
+	codec "go.unistack.org/micro-proto/v4/codec"
 )
 
 var (
 	HealthServiceName = "HealthService"
 )
 
-type HealthServiceClient interface {
-	Healthy(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
-	Live(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
-	Ready(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
-	Version(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
-}
-
 type HealthServiceServer interface {
 	Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 	Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
diff --git a/handler/health/health_micro_http.pb.go b/handler/health/health_micro_http.pb.go
index b9ff281..72b1a64 100644
--- a/handler/health/health_micro_http.pb.go
+++ b/handler/health/health_micro_http.pb.go
@@ -1,21 +1,19 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
-// protoc-gen-go-micro version: v3.10.4
+// protoc-gen-go-micro version: v4.0.2
 // source: health/health.proto
 
 package health_handler
 
 import (
 	context "context"
-	v31 "go.unistack.org/micro-client-http/v3"
-	codec "go.unistack.org/micro-proto/v3/codec"
-	v3 "go.unistack.org/micro-server-http/v3"
-	client "go.unistack.org/micro/v3/client"
-	server "go.unistack.org/micro/v3/server"
-	http "net/http"
+	codec "go.unistack.org/micro-proto/v4/codec"
+	v4 "go.unistack.org/micro-server-http/v4"
+	options "go.unistack.org/micro/v4/options"
+	server "go.unistack.org/micro/v4/server"
 )
 
 var (
-	HealthServiceServerEndpoints = []v3.EndpointMetadata{
+	HealthServiceServerEndpoints = []v4.EndpointMetadata{
 		{
 			Name:   "HealthService.Healthy",
 			Path:   "/health",
@@ -68,87 +66,6 @@ var (
 	}
 )
 
-type healthServiceClient struct {
-	c    client.Client
-	name string
-}
-
-func NewHealthServiceClient(name string, c client.Client) HealthServiceClient {
-	return &healthServiceClient{c: c, name: name}
-}
-
-func (c *healthServiceClient) Healthy(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
-	errmap := make(map[string]interface{}, 1)
-	errmap["default"] = &codec.Frame{}
-	opts = append(opts,
-		v31.ErrorMap(errmap),
-	)
-	opts = append(opts,
-		v31.Method(http.MethodGet),
-		v31.Path("/health"),
-	)
-	rsp := &codec.Frame{}
-	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Healthy", req), rsp, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return rsp, nil
-}
-
-func (c *healthServiceClient) Live(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
-	errmap := make(map[string]interface{}, 1)
-	errmap["default"] = &codec.Frame{}
-	opts = append(opts,
-		v31.ErrorMap(errmap),
-	)
-	opts = append(opts,
-		v31.Method(http.MethodGet),
-		v31.Path("/live"),
-	)
-	rsp := &codec.Frame{}
-	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Live", req), rsp, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return rsp, nil
-}
-
-func (c *healthServiceClient) Ready(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
-	errmap := make(map[string]interface{}, 1)
-	errmap["default"] = &codec.Frame{}
-	opts = append(opts,
-		v31.ErrorMap(errmap),
-	)
-	opts = append(opts,
-		v31.Method(http.MethodGet),
-		v31.Path("/ready"),
-	)
-	rsp := &codec.Frame{}
-	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Ready", req), rsp, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return rsp, nil
-}
-
-func (c *healthServiceClient) Version(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
-	errmap := make(map[string]interface{}, 1)
-	errmap["default"] = &codec.Frame{}
-	opts = append(opts,
-		v31.ErrorMap(errmap),
-	)
-	opts = append(opts,
-		v31.Method(http.MethodGet),
-		v31.Path("/version"),
-	)
-	rsp := &codec.Frame{}
-	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Version", req), rsp, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return rsp, nil
-}
-
 type healthServiceServer struct {
 	HealthServiceServer
 }
@@ -169,7 +86,7 @@ func (h *healthServiceServer) Version(ctx context.Context, req *codec.Frame, rsp
 	return h.HealthServiceServer.Version(ctx, req, rsp)
 }
 
-func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts ...server.HandlerOption) error {
+func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts ...options.Option) error {
 	type healthService interface {
 		Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 		Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
@@ -180,7 +97,7 @@ func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts .
 		healthService
 	}
 	h := &healthServiceServer{sh}
-	var nopts []server.HandlerOption
-	nopts = append(nopts, v3.HandlerEndpoints(HealthServiceServerEndpoints))
-	return s.Handle(s.NewHandler(&HealthService{h}, append(nopts, opts...)...))
+	var nopts []options.Option
+	nopts = append(nopts, v4.HandlerEndpoints(HealthServiceServerEndpoints))
+	return s.Handle(&HealthService{h}, append(nopts, opts...)...)
 }
diff --git a/handler/meter/meter.go b/handler/meter/meter.go
index 737c115..beb3ddd 100644
--- a/handler/meter/meter.go
+++ b/handler/meter/meter.go
@@ -8,10 +8,10 @@ import (
 	"strings"
 	"sync"
 
-	codecpb "go.unistack.org/micro-proto/v3/codec"
-	"go.unistack.org/micro/v3/logger"
-	"go.unistack.org/micro/v3/metadata"
-	"go.unistack.org/micro/v3/meter"
+	codecpb "go.unistack.org/micro-proto/v4/codec"
+	"go.unistack.org/micro/v4/logger"
+	"go.unistack.org/micro/v4/metadata"
+	"go.unistack.org/micro/v4/meter"
 )
 
 const (
@@ -125,8 +125,11 @@ func gzipAccepted(md metadata.Metadata) bool {
 	if !ok {
 		return false
 	}
-	if strings.Contains(a, "gzip") {
-		return true
+	for i := range a {
+		if strings.Contains(a[i], "gzip") {
+			return true
+		}
 	}
+
 	return false
 }
diff --git a/handler/meter/meter.proto b/handler/meter/meter.proto
index ef08f72..522bb6a 100644
--- a/handler/meter/meter.proto
+++ b/handler/meter/meter.proto
@@ -1,7 +1,7 @@
 syntax = "proto3";
 
 package micro.server.http.v3.handler.meter;
-option go_package = "go.unistack.org/micro-server-http/v3/handler/meter;meter_handler";
+option go_package = "go.unistack.org/micro-server-http/v4/handler/meter;meter_handler";
 
 import "api/annotations.proto";
 import "openapiv3/annotations.proto";
diff --git a/handler/meter/meter_micro.pb.go b/handler/meter/meter_micro.pb.go
index fb627ef..c9e262b 100644
--- a/handler/meter/meter_micro.pb.go
+++ b/handler/meter/meter_micro.pb.go
@@ -1,25 +1,20 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-micro v3.10.4
-// - protoc              v5.28.3
+// - protoc-gen-go-micro v4.0.2
+// - protoc              v3.21.12
 // source: meter/meter.proto
 
 package meter_handler
 
 import (
 	context "context"
-	codec "go.unistack.org/micro-proto/v3/codec"
-	client "go.unistack.org/micro/v3/client"
+	codec "go.unistack.org/micro-proto/v4/codec"
 )
 
 var (
 	MeterServiceName = "MeterService"
 )
 
-type MeterServiceClient interface {
-	Metrics(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
-}
-
 type MeterServiceServer interface {
 	Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 }
diff --git a/handler/meter/meter_micro_http.pb.go b/handler/meter/meter_micro_http.pb.go
index 2eccdf6..979e421 100644
--- a/handler/meter/meter_micro_http.pb.go
+++ b/handler/meter/meter_micro_http.pb.go
@@ -1,21 +1,19 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
-// protoc-gen-go-micro version: v3.10.4
+// protoc-gen-go-micro version: v4.0.2
 // source: meter/meter.proto
 
 package meter_handler
 
 import (
 	context "context"
-	v31 "go.unistack.org/micro-client-http/v3"
-	codec "go.unistack.org/micro-proto/v3/codec"
-	v3 "go.unistack.org/micro-server-http/v3"
-	client "go.unistack.org/micro/v3/client"
-	server "go.unistack.org/micro/v3/server"
-	http "net/http"
+	codec "go.unistack.org/micro-proto/v4/codec"
+	v4 "go.unistack.org/micro-server-http/v4"
+	options "go.unistack.org/micro/v4/options"
+	server "go.unistack.org/micro/v4/server"
 )
 
 var (
-	MeterServiceServerEndpoints = []v3.EndpointMetadata{
+	MeterServiceServerEndpoints = []v4.EndpointMetadata{
 		{
 			Name:   "MeterService.Metrics",
 			Path:   "/metrics",
@@ -26,33 +24,6 @@ var (
 	}
 )
 
-type meterServiceClient struct {
-	c    client.Client
-	name string
-}
-
-func NewMeterServiceClient(name string, c client.Client) MeterServiceClient {
-	return &meterServiceClient{c: c, name: name}
-}
-
-func (c *meterServiceClient) Metrics(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
-	errmap := make(map[string]interface{}, 1)
-	errmap["default"] = &codec.Frame{}
-	opts = append(opts,
-		v31.ErrorMap(errmap),
-	)
-	opts = append(opts,
-		v31.Method(http.MethodGet),
-		v31.Path("/metrics"),
-	)
-	rsp := &codec.Frame{}
-	err := c.c.Call(ctx, c.c.NewRequest(c.name, "MeterService.Metrics", req), rsp, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return rsp, nil
-}
-
 type meterServiceServer struct {
 	MeterServiceServer
 }
@@ -61,7 +32,7 @@ func (h *meterServiceServer) Metrics(ctx context.Context, req *codec.Frame, rsp
 	return h.MeterServiceServer.Metrics(ctx, req, rsp)
 }
 
-func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...server.HandlerOption) error {
+func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...options.Option) error {
 	type meterService interface {
 		Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 	}
@@ -69,7 +40,7 @@ func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...
 		meterService
 	}
 	h := &meterServiceServer{sh}
-	var nopts []server.HandlerOption
-	nopts = append(nopts, v3.HandlerEndpoints(MeterServiceServerEndpoints))
-	return s.Handle(s.NewHandler(&MeterService{h}, append(nopts, opts...)...))
+	var nopts []options.Option
+	nopts = append(nopts, v4.HandlerEndpoints(MeterServiceServerEndpoints))
+	return s.Handle(&MeterService{h}, append(nopts, opts...)...) // TODO cannot use
 }
diff --git a/handler/swagger/swagger.go b/handler/swagger/swagger.go
index 5daf7d1..d432884 100644
--- a/handler/swagger/swagger.go
+++ b/handler/swagger/swagger.go
@@ -5,7 +5,7 @@ import (
 	"net/http"
 
 	yamlcodec "go.unistack.org/micro-codec-yaml/v3"
-	rutil "go.unistack.org/micro/v3/util/reflect"
+	rutil "go.unistack.org/micro/v4/util/reflect"
 )
 
 // Handler append to generated swagger data from dst map[string]interface{}
diff --git a/http.go b/http.go
index 6e69927..aae1c1b 100644
--- a/http.go
+++ b/http.go
@@ -9,18 +9,16 @@ import (
 	"net"
 	"net/http"
 	"reflect"
-	"sort"
 	"strings"
 	"sync"
 	"sync/atomic"
 	"time"
 
-	"go.unistack.org/micro/v3/broker"
-	"go.unistack.org/micro/v3/codec"
-	"go.unistack.org/micro/v3/logger"
-	"go.unistack.org/micro/v3/register"
-	"go.unistack.org/micro/v3/server"
-	rhttp "go.unistack.org/micro/v3/util/http"
+	"go.unistack.org/micro/v4/codec"
+	"go.unistack.org/micro/v4/logger"
+	"go.unistack.org/micro/v4/register"
+	"go.unistack.org/micro/v4/server"
+	rhttp "go.unistack.org/micro/v4/util/http"
 	"golang.org/x/net/netutil"
 )
 
@@ -31,7 +29,6 @@ type Server struct {
 	rsvc         *register.Service
 	handlers     map[string]server.Handler
 	exit         chan chan error
-	subscribers  map[*httpSubscriber][]broker.Subscriber
 	errorHandler func(context.Context, server.Handler, http.ResponseWriter, *http.Request, error, int)
 	pathHandlers *rhttp.Trie
 	opts         server.Options
@@ -172,17 +169,6 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
 
 	tp := reflect.TypeOf(handler)
 
-	/*
-		if len(options.Metadata) == 0 {
-			if h.registerRPC {
-				h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
-				if err := hdlr.handlers.Insert([]string{http.MethodPost}, "/"+hn, pth); err != nil {
-					h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
-				}
-			}
-		}
-	*/
-
 	registerCORS := false
 	if v, ok := options.Context.Value(registerCORSHandlerKey{}).(bool); ok && v {
 		registerCORS = true
@@ -220,13 +206,16 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
 		pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
 		hdlr.name = name
 
-		methods := []string{md["Method"]}
+		methods := md["Method"]
 		if registerCORS {
 			methods = append(methods, http.MethodOptions)
 		}
 
-		if err := hdlr.handlers.Insert(methods, md["Path"], pth); err != nil {
-			h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add handler for %v %s", methods, md["Path"]))
+		pattern := md["Path"]
+		for i := len(pattern) - 1; i >= 0; i-- {
+			if err := hdlr.handlers.Insert(methods, pattern[i], pth); err != nil {
+				h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add handler for %v %s: index %d", methods, md["Path"], i))
+			}
 		}
 
 		if h.registerRPC {
@@ -304,35 +293,6 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
 	return hdlr
 }
 
-func (h *Server) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
-	return newSubscriber(topic, handler, opts...)
-}
-
-func (h *Server) Subscribe(sb server.Subscriber) error {
-	sub, ok := sb.(*httpSubscriber)
-	if !ok {
-		return fmt.Errorf("invalid subscriber: expected *httpSubscriber")
-	}
-	if len(sub.handlers) == 0 {
-		return fmt.Errorf("invalid subscriber: no handler functions")
-	}
-
-	if err := server.ValidateSubscriber(sb); err != nil {
-		return err
-	}
-
-	h.RLock()
-	_, ok = h.subscribers[sub]
-	h.RUnlock()
-	if ok {
-		return fmt.Errorf("subscriber %v already exists", h)
-	}
-	h.Lock()
-	h.subscribers[sub] = nil
-	h.Unlock()
-	return nil
-}
-
 func (h *Server) Register() error {
 	h.RLock()
 	rsvc := h.rsvc
@@ -352,18 +312,6 @@ func (h *Server) Register() error {
 		return err
 	}
 
-	h.Lock()
-	subscriberList := make([]*httpSubscriber, 0, len(h.subscribers))
-	for e := range h.subscribers {
-		// Only advertise non internal subscribers
-		subscriberList = append(subscriberList, e)
-	}
-	sort.Slice(subscriberList, func(i, j int) bool {
-		return subscriberList[i].topic > subscriberList[j].topic
-	})
-
-	h.Unlock()
-
 	h.RLock()
 	registered := h.registered
 	h.RUnlock()
@@ -393,35 +341,6 @@ func (h *Server) Register() error {
 	return nil
 }
 
-func (h *Server) subscribe() error {
-	config := h.opts
-
-	for sb := range h.subscribers {
-		handler := h.createSubHandler(sb, config)
-		var opts []broker.SubscribeOption
-		if queue := sb.Options().Queue; len(queue) > 0 {
-			opts = append(opts, broker.SubscribeGroup(queue))
-		}
-
-		subCtx := config.Context
-		if cx := sb.Options().Context; cx != nil {
-			subCtx = cx
-		}
-		opts = append(opts, broker.SubscribeContext(subCtx))
-		opts = append(opts, broker.SubscribeAutoAck(sb.Options().AutoAck))
-		opts = append(opts, broker.SubscribeBodyOnly(sb.Options().BodyOnly))
-
-		sub, err := config.Broker.Subscribe(subCtx, sb.Topic(), handler, opts...)
-		if err != nil {
-			h.Unlock()
-			return err
-		}
-		h.subscribers[sb] = []broker.Subscriber{sub}
-	}
-
-	return nil
-}
-
 func (h *Server) Deregister() error {
 	h.RLock()
 	config := h.opts
@@ -450,22 +369,6 @@ func (h *Server) Deregister() error {
 
 	h.registered = false
 
-	subCtx := h.opts.Context
-	for sb, subs := range h.subscribers {
-		if cx := sb.Options().Context; cx != nil {
-			subCtx = cx
-		}
-
-		for _, sub := range subs {
-			config.Logger.Info(config.Context, "Unsubscribing from topic: "+sub.Topic())
-			if err := sub.Unsubscribe(subCtx); err != nil {
-				h.Unlock()
-				config.Logger.Error(config.Context, fmt.Sprintf("failed to unsubscribe topic: %s, error", sb.Topic()), err)
-				return err
-			}
-		}
-		h.subscribers[sb] = nil
-	}
 	h.Unlock()
 	return nil
 }
@@ -552,10 +455,6 @@ func (h *Server) Start() error {
 		}
 	}
 
-	if err := h.subscribe(); err != nil {
-		return err
-	}
-
 	fn := handler
 
 	var hs *http.Server
@@ -701,7 +600,6 @@ func NewServer(opts ...server.Option) *Server {
 		stateHealth:  &atomic.Uint32{},
 		opts:         options,
 		exit:         make(chan chan error),
-		subscribers:  make(map[*httpSubscriber][]broker.Subscriber),
 		errorHandler: eh,
 		pathHandlers: rhttp.NewTrie(),
 	}
diff --git a/message.go b/message.go
index 226d6b1..394c788 100644
--- a/message.go
+++ b/message.go
@@ -1,8 +1,8 @@
 package http
 
 import (
-	"go.unistack.org/micro/v3/codec"
-	"go.unistack.org/micro/v3/metadata"
+	"go.unistack.org/micro/v4/codec"
+	"go.unistack.org/micro/v4/metadata"
 )
 
 type httpMessage struct {
diff --git a/options.go b/options.go
index 98908df..658e263 100644
--- a/options.go
+++ b/options.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"net/http"
 
-	"go.unistack.org/micro/v3/server"
+	"go.unistack.org/micro/v4/server"
 )
 
 // SetError pass error to caller
diff --git a/request.go b/request.go
index 40a7ff9..f4ca3bd 100644
--- a/request.go
+++ b/request.go
@@ -1,14 +1,13 @@
 package http
 
 import (
-	"go.unistack.org/micro/v3/codec"
-	"go.unistack.org/micro/v3/metadata"
-	"go.unistack.org/micro/v3/server"
+	"go.unistack.org/micro/v4/codec"
+	"go.unistack.org/micro/v4/metadata"
+	"go.unistack.org/micro/v4/server"
 )
 
 var (
 	_ server.Request = &rpcRequest{}
-	_ server.Message = &rpcMessage{}
 )
 
 type rpcRequest struct {
diff --git a/server.go b/server.go
index 7508467..8669be3 100644
--- a/server.go
+++ b/server.go
@@ -7,9 +7,11 @@ import (
 	"unicode"
 	"unicode/utf8"
 
-	"go.unistack.org/micro/v3/server"
+	"go.unistack.org/micro/v4/server"
 )
 
+var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
+
 type methodType struct {
 	ArgType     reflect.Type
 	ReplyType   reflect.Type
diff --git a/subscriber.go b/subscriber.go
deleted file mode 100644
index 4ddee71..0000000
--- a/subscriber.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package http
-
-import (
-	"context"
-	"fmt"
-	"reflect"
-	"strings"
-
-	"go.unistack.org/micro/v3/broker"
-	"go.unistack.org/micro/v3/metadata"
-	"go.unistack.org/micro/v3/options"
-	"go.unistack.org/micro/v3/server"
-)
-
-var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
-
-type handler struct {
-	reqType reflect.Type
-	ctxType reflect.Type
-	method  reflect.Value
-}
-
-type httpSubscriber struct {
-	topic      string
-	rcvr       reflect.Value
-	typ        reflect.Type
-	subscriber interface{}
-	handlers   []*handler
-	opts       server.SubscriberOptions
-}
-
-func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
-	options := server.NewSubscriberOptions(opts...)
-
-	var handlers []*handler
-
-	if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
-		h := &handler{
-			method: reflect.ValueOf(sub),
-		}
-
-		switch typ.NumIn() {
-		case 1:
-			h.reqType = typ.In(0)
-		case 2:
-			h.ctxType = typ.In(0)
-			h.reqType = typ.In(1)
-		}
-
-		handlers = append(handlers, h)
-	} else {
-		for m := 0; m < typ.NumMethod(); m++ {
-			method := typ.Method(m)
-			h := &handler{
-				method: method.Func,
-			}
-
-			switch method.Type.NumIn() {
-			case 2:
-				h.reqType = method.Type.In(1)
-			case 3:
-				h.ctxType = method.Type.In(1)
-				h.reqType = method.Type.In(2)
-			}
-
-			handlers = append(handlers, h)
-		}
-	}
-
-	return &httpSubscriber{
-		rcvr:       reflect.ValueOf(sub),
-		typ:        reflect.TypeOf(sub),
-		topic:      topic,
-		subscriber: sub,
-		handlers:   handlers,
-		opts:       options,
-	}
-}
-
-func (s *Server) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
-	return func(p broker.Event) error {
-		msg := p.Message()
-		ct := msg.Header["Content-Type"]
-		cf, err := s.newCodec(ct)
-		if err != nil {
-			return err
-		}
-
-		hdr := metadata.Copy(msg.Header)
-		ctx := metadata.NewIncomingContext(context.Background(), hdr)
-
-		results := make(chan error, len(sb.handlers))
-
-		for i := 0; i < len(sb.handlers); i++ {
-			handler := sb.handlers[i]
-
-			var isVal bool
-			var req reflect.Value
-
-			if handler.reqType.Kind() == reflect.Ptr {
-				req = reflect.New(handler.reqType.Elem())
-			} else {
-				req = reflect.New(handler.reqType)
-				isVal = true
-			}
-			if isVal {
-				req = req.Elem()
-			}
-
-			if err := cf.Unmarshal(msg.Body, req.Interface()); err != nil {
-				return err
-			}
-
-			fn := func(ctx context.Context, msg server.Message) error {
-				var vals []reflect.Value
-				if sb.typ.Kind() != reflect.Func {
-					vals = append(vals, sb.rcvr)
-				}
-				if handler.ctxType != nil {
-					vals = append(vals, reflect.ValueOf(ctx))
-				}
-
-				vals = append(vals, reflect.ValueOf(msg.Body()))
-
-				returnValues := handler.method.Call(vals)
-				if err := returnValues[0].Interface(); err != nil {
-					return err.(error)
-				}
-				return nil
-			}
-
-			opts.Hooks.EachPrev(func(hook options.Hook) {
-				if h, ok := hook.(server.HookSubHandler); ok {
-					fn = h(fn)
-				}
-			})
-
-			go func() {
-				results <- fn(ctx, &httpMessage{
-					topic:       sb.topic,
-					contentType: ct,
-					payload:     req.Interface(),
-					header:      msg.Header,
-					codec:       cf,
-				})
-			}()
-		}
-
-		var errors []string
-
-		for i := 0; i < len(sb.handlers); i++ {
-			if err := <-results; err != nil {
-				errors = append(errors, err.Error())
-			}
-		}
-
-		if len(errors) > 0 {
-			return fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
-		}
-
-		return nil
-	}
-}
-
-func (s *httpSubscriber) Topic() string {
-	return s.topic
-}
-
-func (s *httpSubscriber) Subscriber() interface{} {
-	return s.subscriber
-}
-
-func (s *httpSubscriber) Options() server.SubscriberOptions {
-	return s.opts
-}
diff --git a/util.go b/util.go
index 99576d3..4357316 100644
--- a/util.go
+++ b/util.go
@@ -5,8 +5,8 @@ import (
 	"net/http"
 	"strings"
 
-	"go.unistack.org/micro/v3/metadata"
-	rutil "go.unistack.org/micro/v3/util/reflect"
+	"go.unistack.org/micro/v4/metadata"
+	rutil "go.unistack.org/micro/v4/util/reflect"
 )
 
 func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption) error {
@@ -31,23 +31,26 @@ func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption
 		}
 	}
 
-	cookies := strings.Split(md["Cookie"], ";")
-	cmd := make(map[string]string, len(cookies))
-	for _, cookie := range cookies {
-		kv := strings.Split(cookie, "=")
-		if len(kv) != 2 {
-			continue
+	cookieVals, _ := md["Cookie"]
+	for i := range cookieVals {
+		cookies := strings.Split(cookieVals[i], ";")
+		cmd := make(map[string]string, len(cookies))
+		for _, cookie := range cookies {
+			kv := strings.Split(cookie, "=")
+			if len(kv) != 2 {
+				continue
+			}
+			cmd[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
 		}
-		cmd[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
-	}
-	for idx := 0; idx < len(options.cookies)/2; idx += 2 {
-		k := http.CanonicalHeaderKey(options.cookies[idx])
-		v, ok := cmd[k]
-		if !ok {
-			continue
-		}
-		if err = rutil.SetFieldByPath(req, v, k); err != nil {
-			return err
+		for idx := 0; idx < len(options.cookies)/2; idx += 2 {
+			k := http.CanonicalHeaderKey(options.cookies[idx])
+			v, ok := cmd[k]
+			if !ok {
+				continue
+			}
+			if err = rutil.SetFieldByPath(req, v, k); err != nil {
+				return err
+			}
 		}
 	}
 
diff --git a/util_test.go b/util_test.go
index f19e867..7c72d28 100644
--- a/util_test.go
+++ b/util_test.go
@@ -7,9 +7,9 @@ import (
 	"strings"
 	"testing"
 
-	"go.unistack.org/micro/v3/metadata"
-	"go.unistack.org/micro/v3/options"
-	"go.unistack.org/micro/v3/server"
+	"go.unistack.org/micro/v4/metadata"
+	"go.unistack.org/micro/v4/options"
+	"go.unistack.org/micro/v4/server"
 )
 
 func Test_Hook(t *testing.T) {
-- 
2.47.2


From b2949459e157e0a562ea79f92c0f2c9fad84082f Mon Sep 17 00:00:00 2001
From: Vasiliy Tolstov <v.tolstov@unistack.org>
Date: Fri, 28 Feb 2025 18:44:38 +0300
Subject: [PATCH 2/4] fixup

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
---
 util.go | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/util.go b/util.go
index 4357316..4d8f645 100644
--- a/util.go
+++ b/util.go
@@ -15,23 +15,30 @@ func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption
 	for _, o := range opts {
 		o(&options)
 	}
+
 	md, ok := metadata.FromIncomingContext(ctx)
 	if !ok {
 		return nil
 	}
 
 	for idx := 0; idx < len(options.headers)/2; idx += 2 {
-		k := http.CanonicalHeaderKey(options.headers[idx])
-		v, ok := md[k]
+		k := options.headers[idx]
+		v, ok := md.Get(k)
 		if !ok {
 			continue
 		}
-		if err = rutil.SetFieldByPath(req, v, k); err != nil {
+
+		if len(v) == 1 {
+			err = rutil.SetFieldByPath(req, v[0], k)
+		} else {
+			err = rutil.SetFieldByPath(req, v, k)
+		}
+		if err != nil {
 			return err
 		}
 	}
 
-	cookieVals, _ := md["Cookie"]
+	cookieVals, _ := md.Get("Cookie")
 	for i := range cookieVals {
 		cookies := strings.Split(cookieVals[i], ";")
 		cmd := make(map[string]string, len(cookies))
@@ -45,10 +52,13 @@ func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption
 		for idx := 0; idx < len(options.cookies)/2; idx += 2 {
 			k := http.CanonicalHeaderKey(options.cookies[idx])
 			v, ok := cmd[k]
+
 			if !ok {
 				continue
 			}
-			if err = rutil.SetFieldByPath(req, v, k); err != nil {
+
+			err = rutil.SetFieldByPath(req, v, k)
+			if err != nil {
 				return err
 			}
 		}
-- 
2.47.2


From fa9081cb99eb2c3d1362642a87cecc23702d25ec Mon Sep 17 00:00:00 2001
From: Vasiliy Tolstov <v.tolstov@unistack.org>
Date: Sun, 2 Mar 2025 01:00:13 +0300
Subject: [PATCH 3/4] update

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
---
 go.mod                                 | 19 +++---
 go.sum                                 | 42 +++++++-----
 handler/health/health_micro.pb.go      | 12 +++-
 handler/health/health_micro_http.pb.go | 94 ++++++++++++++++++++++++--
 handler/meter/meter_micro.pb.go        |  9 ++-
 handler/meter/meter_micro_http.pb.go   | 40 +++++++++--
 handler/swagger/swagger.go             |  2 +-
 7 files changed, 174 insertions(+), 44 deletions(-)

diff --git a/go.mod b/go.mod
index 8fccbcd..090fe7b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,12 +1,13 @@
 module go.unistack.org/micro-server-http/v4
 
-go 1.22.2
+go 1.23.0
 
 require (
-	go.unistack.org/micro-codec-yaml/v3 v3.10.3
+	go.unistack.org/micro-client-http/v4 v4.1.0
+	go.unistack.org/micro-codec-yaml/v4 v4.0.0
 	go.unistack.org/micro-proto/v4 v4.1.0
 	go.unistack.org/micro/v4 v4.1.2
-	golang.org/x/net v0.34.0
+	golang.org/x/net v0.35.0
 )
 
 require (
@@ -16,11 +17,11 @@ require (
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/matoous/go-nanoid v1.5.1 // indirect
 	github.com/spf13/cast v1.7.1 // indirect
-	go.unistack.org/micro-proto/v3 v3.4.1 // indirect
-	go.unistack.org/micro/v3 v3.11.30 // indirect
-	golang.org/x/sys v0.29.0 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
-	google.golang.org/grpc v1.69.4 // indirect
-	google.golang.org/protobuf v1.36.3 // indirect
+	golang.org/x/sys v0.30.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e // indirect
+	google.golang.org/grpc v1.70.0 // indirect
+	google.golang.org/protobuf v1.36.5 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	sigs.k8s.io/yaml v1.4.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 6068486..469633d 100644
--- a/go.sum
+++ b/go.sum
@@ -639,6 +639,8 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -876,14 +878,12 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
-go.unistack.org/micro-codec-yaml/v3 v3.10.3 h1:H0jM4wCSReHzEc1hnKYgXjzg171+tUE6IHxdxvgq/cQ=
-go.unistack.org/micro-codec-yaml/v3 v3.10.3/go.mod h1:pruYGvCULoHa6Tfah1UnTrwCzQhy0KT6D4UXEMgf+tk=
-go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q=
-go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
+go.unistack.org/micro-client-http/v4 v4.1.0 h1:u1YwMmhPaQn0T0m6OSC6MBijHshDpwiNWMNib7KmSj8=
+go.unistack.org/micro-client-http/v4 v4.1.0/go.mod h1:RtddTKxsN5Zc6bzEON6CqpDL/Svfo13QoGXbIO1x3Os=
+go.unistack.org/micro-codec-yaml/v4 v4.0.0 h1:DK/+fA69gmnvYmGHe3kqVR0pukS8ank5lPG4MfdPQEk=
+go.unistack.org/micro-codec-yaml/v4 v4.0.0/go.mod h1:UG4ouILbUfgNL7nvp7CpmD2IIzO8bQHjzDIahOvIAgM=
 go.unistack.org/micro-proto/v4 v4.1.0 h1:qPwL2n/oqh9RE3RTTDgt28XK3QzV597VugQPaw9lKUk=
 go.unistack.org/micro-proto/v4 v4.1.0/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec=
-go.unistack.org/micro/v3 v3.11.30 h1:XTLgZubSGzQL85IUMp1pTJnS1lP4eFwTZyelV/SzOMc=
-go.unistack.org/micro/v3 v3.11.30/go.mod h1:fvOkXKs3wKHToWH6Mxy+aovEiDl2q4UlOCdVfJdziBU=
 go.unistack.org/micro/v4 v4.1.2 h1:9SOlPYyPNNFpg1A7BsvhDyQm3gysLH1AhWbDCp1hyoY=
 go.unistack.org/micro/v4 v4.1.2/go.mod h1:lr3oYED8Ay1vjK68QqRw30QOtdk/ffpZqMFDasOUhKw=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -1007,8 +1007,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
-golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1128,8 +1128,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -1151,8 +1151,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1436,8 +1436,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.
 google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e h1:YA5lmSs3zc/5w+xsRcHqpETkaYyK63ivEPzNTcUUlSA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1477,8 +1477,8 @@ google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
 google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
-google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
-google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
+google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
+google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1497,8 +1497,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
-google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -1506,6 +1506,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
@@ -1556,3 +1558,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/handler/health/health_micro.pb.go b/handler/health/health_micro.pb.go
index c226578..bf98b2c 100644
--- a/handler/health/health_micro.pb.go
+++ b/handler/health/health_micro.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-micro v4.0.2
-// - protoc              v3.21.12
+// - protoc-gen-go-micro v4.1.0
+// - protoc              v5.29.3
 // source: health/health.proto
 
 package health_handler
@@ -9,12 +9,20 @@ package health_handler
 import (
 	context "context"
 	codec "go.unistack.org/micro-proto/v4/codec"
+	client "go.unistack.org/micro/v4/client"
 )
 
 var (
 	HealthServiceName = "HealthService"
 )
 
+type HealthServiceClient interface {
+	Healthy(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
+	Live(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
+	Ready(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
+	Version(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
+}
+
 type HealthServiceServer interface {
 	Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 	Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
diff --git a/handler/health/health_micro_http.pb.go b/handler/health/health_micro_http.pb.go
index 72b1a64..26e3139 100644
--- a/handler/health/health_micro_http.pb.go
+++ b/handler/health/health_micro_http.pb.go
@@ -1,15 +1,17 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
-// protoc-gen-go-micro version: v4.0.2
+// protoc-gen-go-micro version: v4.1.0
 // source: health/health.proto
 
 package health_handler
 
 import (
 	context "context"
+	v41 "go.unistack.org/micro-client-http/v4"
 	codec "go.unistack.org/micro-proto/v4/codec"
 	v4 "go.unistack.org/micro-server-http/v4"
-	options "go.unistack.org/micro/v4/options"
+	client "go.unistack.org/micro/v4/client"
 	server "go.unistack.org/micro/v4/server"
+	http "net/http"
 )
 
 var (
@@ -66,6 +68,87 @@ var (
 	}
 )
 
+type healthServiceClient struct {
+	c    client.Client
+	name string
+}
+
+func NewHealthServiceClient(name string, c client.Client) HealthServiceClient {
+	return &healthServiceClient{c: c, name: name}
+}
+
+func (c *healthServiceClient) Healthy(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
+	errmap := make(map[string]interface{}, 1)
+	errmap["default"] = &codec.Frame{}
+	opts = append(opts,
+		v41.ErrorMap(errmap),
+	)
+	opts = append(opts,
+		v41.Method(http.MethodGet),
+		v41.Path("/health"),
+	)
+	rsp := &codec.Frame{}
+	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Healthy", req), rsp, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return rsp, nil
+}
+
+func (c *healthServiceClient) Live(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
+	errmap := make(map[string]interface{}, 1)
+	errmap["default"] = &codec.Frame{}
+	opts = append(opts,
+		v41.ErrorMap(errmap),
+	)
+	opts = append(opts,
+		v41.Method(http.MethodGet),
+		v41.Path("/live"),
+	)
+	rsp := &codec.Frame{}
+	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Live", req), rsp, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return rsp, nil
+}
+
+func (c *healthServiceClient) Ready(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
+	errmap := make(map[string]interface{}, 1)
+	errmap["default"] = &codec.Frame{}
+	opts = append(opts,
+		v41.ErrorMap(errmap),
+	)
+	opts = append(opts,
+		v41.Method(http.MethodGet),
+		v41.Path("/ready"),
+	)
+	rsp := &codec.Frame{}
+	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Ready", req), rsp, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return rsp, nil
+}
+
+func (c *healthServiceClient) Version(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
+	errmap := make(map[string]interface{}, 1)
+	errmap["default"] = &codec.Frame{}
+	opts = append(opts,
+		v41.ErrorMap(errmap),
+	)
+	opts = append(opts,
+		v41.Method(http.MethodGet),
+		v41.Path("/version"),
+	)
+	rsp := &codec.Frame{}
+	err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Version", req), rsp, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return rsp, nil
+}
+
 type healthServiceServer struct {
 	HealthServiceServer
 }
@@ -86,7 +169,7 @@ func (h *healthServiceServer) Version(ctx context.Context, req *codec.Frame, rsp
 	return h.HealthServiceServer.Version(ctx, req, rsp)
 }
 
-func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts ...options.Option) error {
+func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts ...server.HandlerOption) error {
 	type healthService interface {
 		Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 		Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
@@ -97,7 +180,6 @@ func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts .
 		healthService
 	}
 	h := &healthServiceServer{sh}
-	var nopts []options.Option
-	nopts = append(nopts, v4.HandlerEndpoints(HealthServiceServerEndpoints))
-	return s.Handle(&HealthService{h}, append(nopts, opts...)...)
+	opts = append(opts, v4.HandlerEndpoints(HealthServiceServerEndpoints))
+	return s.Handle(s.NewHandler(&HealthService{h}, opts...))
 }
diff --git a/handler/meter/meter_micro.pb.go b/handler/meter/meter_micro.pb.go
index c9e262b..f12de2a 100644
--- a/handler/meter/meter_micro.pb.go
+++ b/handler/meter/meter_micro.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-micro v4.0.2
-// - protoc              v3.21.12
+// - protoc-gen-go-micro v4.1.0
+// - protoc              v5.29.3
 // source: meter/meter.proto
 
 package meter_handler
@@ -9,12 +9,17 @@ package meter_handler
 import (
 	context "context"
 	codec "go.unistack.org/micro-proto/v4/codec"
+	client "go.unistack.org/micro/v4/client"
 )
 
 var (
 	MeterServiceName = "MeterService"
 )
 
+type MeterServiceClient interface {
+	Metrics(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
+}
+
 type MeterServiceServer interface {
 	Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 }
diff --git a/handler/meter/meter_micro_http.pb.go b/handler/meter/meter_micro_http.pb.go
index 979e421..1e9d59a 100644
--- a/handler/meter/meter_micro_http.pb.go
+++ b/handler/meter/meter_micro_http.pb.go
@@ -1,15 +1,17 @@
 // Code generated by protoc-gen-go-micro. DO NOT EDIT.
-// protoc-gen-go-micro version: v4.0.2
+// protoc-gen-go-micro version: v4.1.0
 // source: meter/meter.proto
 
 package meter_handler
 
 import (
 	context "context"
+	v41 "go.unistack.org/micro-client-http/v4"
 	codec "go.unistack.org/micro-proto/v4/codec"
 	v4 "go.unistack.org/micro-server-http/v4"
-	options "go.unistack.org/micro/v4/options"
+	client "go.unistack.org/micro/v4/client"
 	server "go.unistack.org/micro/v4/server"
+	http "net/http"
 )
 
 var (
@@ -24,6 +26,33 @@ var (
 	}
 )
 
+type meterServiceClient struct {
+	c    client.Client
+	name string
+}
+
+func NewMeterServiceClient(name string, c client.Client) MeterServiceClient {
+	return &meterServiceClient{c: c, name: name}
+}
+
+func (c *meterServiceClient) Metrics(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
+	errmap := make(map[string]interface{}, 1)
+	errmap["default"] = &codec.Frame{}
+	opts = append(opts,
+		v41.ErrorMap(errmap),
+	)
+	opts = append(opts,
+		v41.Method(http.MethodGet),
+		v41.Path("/metrics"),
+	)
+	rsp := &codec.Frame{}
+	err := c.c.Call(ctx, c.c.NewRequest(c.name, "MeterService.Metrics", req), rsp, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return rsp, nil
+}
+
 type meterServiceServer struct {
 	MeterServiceServer
 }
@@ -32,7 +61,7 @@ func (h *meterServiceServer) Metrics(ctx context.Context, req *codec.Frame, rsp
 	return h.MeterServiceServer.Metrics(ctx, req, rsp)
 }
 
-func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...options.Option) error {
+func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...server.HandlerOption) error {
 	type meterService interface {
 		Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
 	}
@@ -40,7 +69,6 @@ func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...
 		meterService
 	}
 	h := &meterServiceServer{sh}
-	var nopts []options.Option
-	nopts = append(nopts, v4.HandlerEndpoints(MeterServiceServerEndpoints))
-	return s.Handle(&MeterService{h}, append(nopts, opts...)...) // TODO cannot use
+	opts = append(opts, v4.HandlerEndpoints(MeterServiceServerEndpoints))
+	return s.Handle(s.NewHandler(&MeterService{h}, opts...))
 }
diff --git a/handler/swagger/swagger.go b/handler/swagger/swagger.go
index d432884..c41e142 100644
--- a/handler/swagger/swagger.go
+++ b/handler/swagger/swagger.go
@@ -4,7 +4,7 @@ import (
 	"io/fs"
 	"net/http"
 
-	yamlcodec "go.unistack.org/micro-codec-yaml/v3"
+	yamlcodec "go.unistack.org/micro-codec-yaml/v4"
 	rutil "go.unistack.org/micro/v4/util/reflect"
 )
 
-- 
2.47.2


From a87eaaa3d47aa138919061b2761c573a02c8268a Mon Sep 17 00:00:00 2001
From: Vasiliy Tolstov <v.tolstov@unistack.org>
Date: Sun, 2 Mar 2025 01:07:19 +0300
Subject: [PATCH 4/4] update

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
---
 go.mod     |  4 +---
 go.sum     | 12 ++----------
 message.go | 34 ----------------------------------
 request.go | 32 +-------------------------------
 4 files changed, 4 insertions(+), 78 deletions(-)
 delete mode 100644 message.go

diff --git a/go.mod b/go.mod
index 090fe7b..f2870b3 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.23.0
 
 require (
 	go.unistack.org/micro-client-http/v4 v4.1.0
-	go.unistack.org/micro-codec-yaml/v4 v4.0.0
+	go.unistack.org/micro-codec-yaml/v4 v4.1.0
 	go.unistack.org/micro-proto/v4 v4.1.0
 	go.unistack.org/micro/v4 v4.1.2
 	golang.org/x/net v0.35.0
@@ -21,7 +21,5 @@ require (
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e // indirect
 	google.golang.org/grpc v1.70.0 // indirect
 	google.golang.org/protobuf v1.36.5 // indirect
-	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	sigs.k8s.io/yaml v1.4.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 469633d..632f2eb 100644
--- a/go.sum
+++ b/go.sum
@@ -639,8 +639,6 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -880,8 +878,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.unistack.org/micro-client-http/v4 v4.1.0 h1:u1YwMmhPaQn0T0m6OSC6MBijHshDpwiNWMNib7KmSj8=
 go.unistack.org/micro-client-http/v4 v4.1.0/go.mod h1:RtddTKxsN5Zc6bzEON6CqpDL/Svfo13QoGXbIO1x3Os=
-go.unistack.org/micro-codec-yaml/v4 v4.0.0 h1:DK/+fA69gmnvYmGHe3kqVR0pukS8ank5lPG4MfdPQEk=
-go.unistack.org/micro-codec-yaml/v4 v4.0.0/go.mod h1:UG4ouILbUfgNL7nvp7CpmD2IIzO8bQHjzDIahOvIAgM=
+go.unistack.org/micro-codec-yaml/v4 v4.1.0 h1:9utR2ka47CDEShbuF7QBAfv0lAFp06pXh77e2Byrt2s=
+go.unistack.org/micro-codec-yaml/v4 v4.1.0/go.mod h1:aMd5xKrJiUMvh6PNdYbO3G59JZfjSHRXdmNA4RCr8Mw=
 go.unistack.org/micro-proto/v4 v4.1.0 h1:qPwL2n/oqh9RE3RTTDgt28XK3QzV597VugQPaw9lKUk=
 go.unistack.org/micro-proto/v4 v4.1.0/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec=
 go.unistack.org/micro/v4 v4.1.2 h1:9SOlPYyPNNFpg1A7BsvhDyQm3gysLH1AhWbDCp1hyoY=
@@ -1506,8 +1504,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
@@ -1558,7 +1554,3 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
-sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
-sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
-sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/message.go b/message.go
deleted file mode 100644
index 394c788..0000000
--- a/message.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package http
-
-import (
-	"go.unistack.org/micro/v4/codec"
-	"go.unistack.org/micro/v4/metadata"
-)
-
-type httpMessage struct {
-	payload     interface{}
-	codec       codec.Codec
-	header      metadata.Metadata
-	topic       string
-	contentType string
-}
-
-func (r *httpMessage) Topic() string {
-	return r.topic
-}
-
-func (r *httpMessage) ContentType() string {
-	return r.contentType
-}
-
-func (r *httpMessage) Header() metadata.Metadata {
-	return r.header
-}
-
-func (r *httpMessage) Body() interface{} {
-	return r.payload
-}
-
-func (r *httpMessage) Codec() codec.Codec {
-	return r.codec
-}
diff --git a/request.go b/request.go
index f4ca3bd..db02ded 100644
--- a/request.go
+++ b/request.go
@@ -6,9 +6,7 @@ import (
 	"go.unistack.org/micro/v4/server"
 )
 
-var (
-	_ server.Request = &rpcRequest{}
-)
+var _ server.Request = &rpcRequest{}
 
 type rpcRequest struct {
 	// rw          io.ReadWriter
@@ -22,14 +20,6 @@ type rpcRequest struct {
 	stream      bool
 }
 
-type rpcMessage struct {
-	payload     interface{}
-	codec       codec.Codec
-	header      metadata.Metadata
-	topic       string
-	contentType string
-}
-
 func (r *rpcRequest) ContentType() string {
 	return r.contentType
 }
@@ -65,23 +55,3 @@ func (r *rpcRequest) Stream() bool {
 func (r *rpcRequest) Body() interface{} {
 	return r.payload
 }
-
-func (r *rpcMessage) ContentType() string {
-	return r.contentType
-}
-
-func (r *rpcMessage) Topic() string {
-	return r.topic
-}
-
-func (r *rpcMessage) Body() interface{} {
-	return r.payload
-}
-
-func (r *rpcMessage) Header() metadata.Metadata {
-	return r.header
-}
-
-func (r *rpcMessage) Codec() codec.Codec {
-	return r.codec
-}
-- 
2.47.2