package main import ( "bytes" "html/template" "strings" ) var httpTemplate = ` type {{.ServiceType}}Handler interface { {{range .MethodSets}} {{.Name}}(context.Context, *{{.Request}}) (*{{.Reply}}, error) {{end}} } func New{{.ServiceType}}Handler(srv {{.ServiceType}}Handler, opts ...http1.HandleOption) http.Handler { h := http1.DefaultHandleOptions() for _, o := range opts { o(&h) } r := mux.NewRouter() {{range .Methods}} r.HandleFunc("{{.Path}}", func(w http.ResponseWriter, r *http.Request) { var in {{.Request}} {{if ne (len .Vars) 0}} if err := binding.MapProto(&in, mux.Vars(r)); err != nil { h.Error(w, r, err) return } {{end}} if err := h.Decode(r, &in{{.Body}}); err != nil { h.Error(w, r, err) return } next := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.{{.Name}}(ctx, req.(*{{.Request}})) } if h.Middleware != nil { next = h.Middleware(next) } out, err := next(r.Context(), &in) if err != nil { h.Error(w, r, err) return } if err := h.Encode(w, r, out{{.ResponseBody}}); err != nil { h.Error(w, r, err) } }).Methods("{{.Method}}") {{end}} return r } ` type serviceDesc struct { ServiceType string // Greeter ServiceName string // helloworld.Greeter Metadata string // api/helloworld/helloworld.proto Methods []*methodDesc MethodSets map[string]*methodDesc } type methodDesc struct { // method Name string Num int Vars []string Forms []string Request string Reply string // http_rule Path string Method string Body string ResponseBody string } func (s *serviceDesc) execute() string { s.MethodSets = make(map[string]*methodDesc) for _, m := range s.Methods { s.MethodSets[m.Name] = m } buf := new(bytes.Buffer) tmpl, err := template.New("http").Parse(strings.TrimSpace(httpTemplate)) if err != nil { panic(err) } if err := tmpl.Execute(buf, s); err != nil { panic(err) } return string(buf.Bytes()) }