diff --git a/api/metadata/metadata_http.pb.go b/api/metadata/metadata_http.pb.go index 8485c35b3..f30262c4b 100644 --- a/api/metadata/metadata_http.pb.go +++ b/api/metadata/metadata_http.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-http. DO NOT EDIT. // versions: -// protoc-gen-go-http v2.0.0-rc3 +// protoc-gen-go-http v2.0.0-rc5 package metadata @@ -84,8 +84,10 @@ func NewMetadataHTTPClient(client *http.Client) MetadataHTTPClient { func (c *MetadataHTTPClientImpl) GetServiceDesc(ctx context.Context, in *GetServiceDescRequest, opts ...http.CallOption) (*GetServiceDescReply, error) { var out GetServiceDescReply - path := binding.EncodeURL("/services/{name}", in, true) + pattern := "/services/{name}" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/kratos.api.Metadata/GetServiceDesc")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) if err != nil { return nil, err @@ -95,8 +97,10 @@ func (c *MetadataHTTPClientImpl) GetServiceDesc(ctx context.Context, in *GetServ func (c *MetadataHTTPClientImpl) ListServices(ctx context.Context, in *ListServicesRequest, opts ...http.CallOption) (*ListServicesReply, error) { var out ListServicesReply - path := binding.EncodeURL("/services", in, true) + pattern := "/services" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/kratos.api.Metadata/ListServices")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) if err != nil { return nil, err diff --git a/cmd/protoc-gen-go-http/main.go b/cmd/protoc-gen-go-http/main.go index e8f7455b5..36fb4dc53 100644 --- a/cmd/protoc-gen-go-http/main.go +++ b/cmd/protoc-gen-go-http/main.go @@ -8,7 +8,7 @@ import ( "google.golang.org/protobuf/types/pluginpb" ) -const version = "v2.0.0-rc3" +const version = "v2.0.0-rc5" func main() { showVersion := flag.Bool("version", false, "print the version and exit") diff --git a/cmd/protoc-gen-go-http/template.go b/cmd/protoc-gen-go-http/template.go index 4a3130990..7bfd85f6e 100644 --- a/cmd/protoc-gen-go-http/template.go +++ b/cmd/protoc-gen-go-http/template.go @@ -65,8 +65,10 @@ func New{{.ServiceType}}HTTPClient (client *http.Client) {{.ServiceType}}HTTPCli {{range .MethodSets}} func (c *{{$svrType}}HTTPClientImpl) {{.Name}}(ctx context.Context, in *{{.Request}}, opts ...http.CallOption) (*{{.Reply}}, error) { var out {{.Reply}} - path := binding.EncodeURL("{{.Path}}", in, {{.IsQuery}}) + pattern := "{{.Path}}" + path := binding.EncodeURL(pattern, in, {{.IsQuery}}) opts = append(opts, http.Operation("/{{$svrName}}/{{.Name}}")) + opts = append(opts, http.PathTemplate(pattern)) {{if .HasBody -}} err := c.cc.Invoke(ctx, "{{.Method}}", path, in{{.Body}}, &out{{.ResponseBody}}, opts...) {{else -}} diff --git a/examples/blog/api/blog/v1/blog_http.pb.go b/examples/blog/api/blog/v1/blog_http.pb.go index 3fcd414d3..bea209a5b 100644 --- a/examples/blog/api/blog/v1/blog_http.pb.go +++ b/examples/blog/api/blog/v1/blog_http.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-http. DO NOT EDIT. // versions: -// protoc-gen-go-http v2.0.0-rc3 +// protoc-gen-go-http v2.0.0-rc5 package v1 @@ -156,8 +156,10 @@ func NewBlogServiceHTTPClient(client *http.Client) BlogServiceHTTPClient { func (c *BlogServiceHTTPClientImpl) CreateArticle(ctx context.Context, in *CreateArticleRequest, opts ...http.CallOption) (*CreateArticleReply, error) { var out CreateArticleReply - path := binding.EncodeURL("/v1/article/", in, false) + pattern := "/v1/article/" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/blog.api.v1.BlogService/CreateArticle")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) if err != nil { return nil, err @@ -167,8 +169,10 @@ func (c *BlogServiceHTTPClientImpl) CreateArticle(ctx context.Context, in *Creat func (c *BlogServiceHTTPClientImpl) DeleteArticle(ctx context.Context, in *DeleteArticleRequest, opts ...http.CallOption) (*DeleteArticleReply, error) { var out DeleteArticleReply - path := binding.EncodeURL("/v1/article/{id}", in, false) + pattern := "/v1/article/{id}" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/blog.api.v1.BlogService/DeleteArticle")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "DELETE", path, nil, &out, opts...) if err != nil { return nil, err @@ -178,8 +182,10 @@ func (c *BlogServiceHTTPClientImpl) DeleteArticle(ctx context.Context, in *Delet func (c *BlogServiceHTTPClientImpl) GetArticle(ctx context.Context, in *GetArticleRequest, opts ...http.CallOption) (*GetArticleReply, error) { var out GetArticleReply - path := binding.EncodeURL("/v1/article/{id}", in, true) + pattern := "/v1/article/{id}" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/blog.api.v1.BlogService/GetArticle")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) if err != nil { return nil, err @@ -189,8 +195,10 @@ func (c *BlogServiceHTTPClientImpl) GetArticle(ctx context.Context, in *GetArtic func (c *BlogServiceHTTPClientImpl) ListArticle(ctx context.Context, in *ListArticleRequest, opts ...http.CallOption) (*ListArticleReply, error) { var out ListArticleReply - path := binding.EncodeURL("/v1/article/", in, true) + pattern := "/v1/article/" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/blog.api.v1.BlogService/ListArticle")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) if err != nil { return nil, err @@ -200,8 +208,10 @@ func (c *BlogServiceHTTPClientImpl) ListArticle(ctx context.Context, in *ListArt func (c *BlogServiceHTTPClientImpl) UpdateArticle(ctx context.Context, in *UpdateArticleRequest, opts ...http.CallOption) (*UpdateArticleReply, error) { var out UpdateArticleReply - path := binding.EncodeURL("/v1/article/{id}", in, false) + pattern := "/v1/article/{id}" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/blog.api.v1.BlogService/UpdateArticle")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "PUT", path, in, &out, opts...) if err != nil { return nil, err diff --git a/examples/helloworld/helloworld/helloworld_http.pb.go b/examples/helloworld/helloworld/helloworld_http.pb.go index 555173382..81f78683e 100644 --- a/examples/helloworld/helloworld/helloworld_http.pb.go +++ b/examples/helloworld/helloworld/helloworld_http.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-http. DO NOT EDIT. // versions: -// protoc-gen-go-http v2.0.0-rc3 +// protoc-gen-go-http v2.0.0-rc5 package helloworld @@ -62,8 +62,10 @@ func NewGreeterHTTPClient(client *http.Client) GreeterHTTPClient { func (c *GreeterHTTPClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http.CallOption) (*HelloReply, error) { var out HelloReply - path := binding.EncodeURL("/helloworld/{name}", in, true) + pattern := "/helloworld/{name}" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/helloworld.Greeter/SayHello")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) if err != nil { return nil, err diff --git a/examples/traces/api/message/message_http.pb.go b/examples/traces/api/message/message_http.pb.go index bfa19083c..60a4e4107 100644 --- a/examples/traces/api/message/message_http.pb.go +++ b/examples/traces/api/message/message_http.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-http. DO NOT EDIT. // versions: -// protoc-gen-go-http v2.0.0-rc3 +// protoc-gen-go-http v2.0.0-rc5 package v1 @@ -62,8 +62,10 @@ func NewMessageServiceHTTPClient(client *http.Client) MessageServiceHTTPClient { func (c *MessageServiceHTTPClientImpl) GetUserMessage(ctx context.Context, in *GetUserMessageRequest, opts ...http.CallOption) (*GetUserMessageReply, error) { var out GetUserMessageReply - path := binding.EncodeURL("/v1/message/user/{id}/{count}", in, true) + pattern := "/v1/message/user/{id}/{count}" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/api.message.v1.MessageService/GetUserMessage")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, in, &out, opts...) if err != nil { return nil, err diff --git a/examples/traces/api/user/user_http.pb.go b/examples/traces/api/user/user_http.pb.go index 758b45604..d5c416632 100644 --- a/examples/traces/api/user/user_http.pb.go +++ b/examples/traces/api/user/user_http.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-http. DO NOT EDIT. // versions: -// protoc-gen-go-http v2.0.0-rc3 +// protoc-gen-go-http v2.0.0-rc5 package v1 @@ -62,8 +62,10 @@ func NewUserHTTPClient(client *http.Client) UserHTTPClient { func (c *UserHTTPClientImpl) GetMyMessages(ctx context.Context, in *GetMyMessagesRequest, opts ...http.CallOption) (*GetMyMessagesReply, error) { var out GetMyMessagesReply - path := binding.EncodeURL("/v1/user/get/message/{count}", in, true) + pattern := "/v1/user/get/message/{count}" + path := binding.EncodeURL(pattern, in, true) opts = append(opts, http.Operation("/api.user.v1.User/GetMyMessages")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "GET", path, in, &out, opts...) if err != nil { return nil, err diff --git a/internal/testproto/echo_service_http.pb.go b/internal/testproto/echo_service_http.pb.go index 819db2c8b..c12452fdc 100644 --- a/internal/testproto/echo_service_http.pb.go +++ b/internal/testproto/echo_service_http.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-http. DO NOT EDIT. // versions: -// protoc-gen-go-http v2.0.0-rc3 +// protoc-gen-go-http v2.0.0-rc5 package testproto @@ -245,8 +245,10 @@ func NewEchoServiceHTTPClient(client *http.Client) EchoServiceHTTPClient { func (c *EchoServiceHTTPClientImpl) Echo(ctx context.Context, in *SimpleMessage, opts ...http.CallOption) (*SimpleMessage, error) { var out SimpleMessage - path := binding.EncodeURL("/v1/example/echo/{id}", in, false) + pattern := "/v1/example/echo/{id}" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/testproto.EchoService/Echo")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "POST", path, nil, &out, opts...) if err != nil { return nil, err @@ -256,8 +258,10 @@ func (c *EchoServiceHTTPClientImpl) Echo(ctx context.Context, in *SimpleMessage, func (c *EchoServiceHTTPClientImpl) EchoBody(ctx context.Context, in *SimpleMessage, opts ...http.CallOption) (*SimpleMessage, error) { var out SimpleMessage - path := binding.EncodeURL("/v1/example/echo_body", in, false) + pattern := "/v1/example/echo_body" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/testproto.EchoService/EchoBody")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) if err != nil { return nil, err @@ -267,8 +271,10 @@ func (c *EchoServiceHTTPClientImpl) EchoBody(ctx context.Context, in *SimpleMess func (c *EchoServiceHTTPClientImpl) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...http.CallOption) (*SimpleMessage, error) { var out SimpleMessage - path := binding.EncodeURL("/v1/example/echo_delete/{id}/{num}", in, false) + pattern := "/v1/example/echo_delete/{id}/{num}" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/testproto.EchoService/EchoDelete")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "DELETE", path, nil, &out, opts...) if err != nil { return nil, err @@ -278,8 +284,10 @@ func (c *EchoServiceHTTPClientImpl) EchoDelete(ctx context.Context, in *SimpleMe func (c *EchoServiceHTTPClientImpl) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...http.CallOption) (*DynamicMessageUpdate, error) { var out DynamicMessageUpdate - path := binding.EncodeURL("/v1/example/echo_patch", in, false) + pattern := "/v1/example/echo_patch" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/testproto.EchoService/EchoPatch")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "PATCH", path, in.Body, &out, opts...) if err != nil { return nil, err @@ -289,8 +297,10 @@ func (c *EchoServiceHTTPClientImpl) EchoPatch(ctx context.Context, in *DynamicMe func (c *EchoServiceHTTPClientImpl) EchoResponseBody(ctx context.Context, in *DynamicMessageUpdate, opts ...http.CallOption) (*DynamicMessageUpdate, error) { var out DynamicMessageUpdate - path := binding.EncodeURL("/v1/example/echo_response_body", in, false) + pattern := "/v1/example/echo_response_body" + path := binding.EncodeURL(pattern, in, false) opts = append(opts, http.Operation("/testproto.EchoService/EchoResponseBody")) + opts = append(opts, http.PathTemplate(pattern)) err := c.cc.Invoke(ctx, "POST", path, in, &out.Body, opts...) if err != nil { return nil, err diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go index 521be7935..bc16e65e5 100644 --- a/transport/http/binding/encode.go +++ b/transport/http/binding/encode.go @@ -19,16 +19,16 @@ import ( ) // EncodeURL encode proto message to url path. -func EncodeURL(pathPattern string, msg proto.Message, needQuery bool) string { +func EncodeURL(pathTemplate string, msg proto.Message, needQuery bool) string { if msg == nil || (reflect.ValueOf(msg).Kind() == reflect.Ptr && reflect.ValueOf(msg).IsNil()) { - return pathPattern + return pathTemplate } reg := regexp.MustCompile(`/{[.\w]+}`) if reg == nil { - return pathPattern + return pathTemplate } pathParams := make(map[string]struct{}, 0) - path := reg.ReplaceAllStringFunc(pathPattern, func(in string) string { + path := reg.ReplaceAllStringFunc(pathTemplate, func(in string) string { if len(in) < 4 { return in } diff --git a/transport/http/calloption.go b/transport/http/calloption.go index cd2cd72cf..db2a75dbc 100644 --- a/transport/http/calloption.go +++ b/transport/http/calloption.go @@ -13,8 +13,9 @@ type CallOption interface { } type callInfo struct { - contentType string - operation string + contentType string + operation string + pathTemplate string } // EmptyCallOption does not alter the Call configuration. @@ -45,8 +46,9 @@ func (o ContentTypeCallOption) before(c *callInfo) error { func defaultCallInfo(path string) callInfo { return callInfo{ - contentType: "application/json", - operation: path, + contentType: "application/json", + operation: path, + pathTemplate: path, } } @@ -65,3 +67,19 @@ func (o OperationCallOption) before(c *callInfo) error { c.operation = o.Operation return nil } + +// PathTemplate is http path template +func PathTemplate(pattern string) CallOption { + return PathTemplateCallOption{Pattern: pattern} +} + +// PathTemplateCallOption is set path template for client call +type PathTemplateCallOption struct { + EmptyCallOption + Pattern string +} + +func (o PathTemplateCallOption) before(c *callInfo) error { + c.pathTemplate = o.Pattern + return nil +} diff --git a/transport/http/client.go b/transport/http/client.go index a21557e90..e5aa07f45 100644 --- a/transport/http/client.go +++ b/transport/http/client.go @@ -197,10 +197,11 @@ func (client *Client) Invoke(ctx context.Context, method, path string, args inte req.Header.Set("User-Agent", client.opts.userAgent) } ctx = transport.NewClientContext(ctx, &Transport{ - endpoint: client.opts.endpoint, - header: headerCarrier(req.Header), - operation: c.operation, - request: req, + endpoint: client.opts.endpoint, + header: headerCarrier(req.Header), + operation: c.operation, + request: req, + pathTemplate: c.pathTemplate, }) return client.invoke(ctx, req, args, reply, c) } diff --git a/transport/http/server.go b/transport/http/server.go index 93f31e950..f8cc7b35e 100644 --- a/transport/http/server.go +++ b/transport/http/server.go @@ -162,11 +162,17 @@ func (s *Server) filter() mux.MiddlewareFunc { ctx, cancel = context.WithTimeout(ctx, s.timeout) defer cancel() } + pathTemplate := req.URL.Path + if route := mux.CurrentRoute(req); route != nil { + // /path/123 -> /path/{id} + pathTemplate, _ = route.GetPathTemplate() + } tr := &Transport{ - endpoint: s.endpoint.String(), - operation: req.RequestURI, - header: headerCarrier(req.Header), - request: req, + endpoint: s.endpoint.String(), + operation: pathTemplate, + header: headerCarrier(req.Header), + request: req, + pathTemplate: pathTemplate, } if r := mux.CurrentRoute(req); r != nil { if path, err := r.GetPathTemplate(); err == nil { diff --git a/transport/http/transport.go b/transport/http/transport.go index 743cd316f..4080ee4bd 100644 --- a/transport/http/transport.go +++ b/transport/http/transport.go @@ -13,10 +13,11 @@ var ( // Transport is an HTTP transport. type Transport struct { - endpoint string - operation string - header headerCarrier - request *http.Request + endpoint string + operation string + header headerCarrier + request *http.Request + pathTemplate string } // Kind returns the transport kind. @@ -44,6 +45,11 @@ func (tr *Transport) Request() *http.Request { return tr.request } +// PathTemplate returns the http path template. +func (tr *Transport) PathTemplate() string { + return tr.pathTemplate +} + // SetOperation sets the transport operation. func SetOperation(ctx context.Context, op string) { if tr, ok := transport.FromServerContext(ctx); ok {