api/router/static: allow to specify body dst (#1486)

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2020-04-07 17:38:27 +03:00 committed by GitHub
parent aaee01b1a7
commit 6aaad7d63f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 2 deletions

View File

@ -22,7 +22,7 @@ type Api interface {
String() string String() string
} }
type Options struct {} type Options struct{}
type Option func(*Options) error type Option func(*Options) error
@ -40,6 +40,10 @@ type Endpoint struct {
Method []string Method []string
// HTTP Path e.g /greeter. Expect POSIX regex // HTTP Path e.g /greeter. Expect POSIX regex
Path []string Path []string
// Body destination
// "*" or "" - top level message value
// "string" - inner message value
Body string
// Stream flag // Stream flag
Stream bool Stream bool
} }

View File

@ -300,6 +300,7 @@ func requestPayload(r *http.Request) ([]byte, error) {
// allocate maximum // allocate maximum
matches := make(map[string]interface{}, len(md)) matches := make(map[string]interface{}, len(md))
bodydst := ""
// get fields from url path // get fields from url path
for k, v := range md { for k, v := range md {
@ -307,6 +308,9 @@ func requestPayload(r *http.Request) ([]byte, error) {
if strings.HasPrefix(k, "x-api-field-") { if strings.HasPrefix(k, "x-api-field-") {
matches[strings.TrimPrefix(k, "x-api-field-")] = v matches[strings.TrimPrefix(k, "x-api-field-")] = v
delete(md, k) delete(md, k)
} else if k == "x-api-body" {
bodydst = v
delete(md, k)
} }
} }
@ -387,8 +391,32 @@ func requestPayload(r *http.Request) ([]byte, error) {
} else { } else {
return []byte{}, nil return []byte{}, nil
} }
if bodydst == "" || bodydst == "*" {
if out, err = jsonpatch.MergeMergePatches(out, bodybuf); err == nil {
return out, nil
}
}
dstmap := make(map[string]interface{})
ps := strings.Split(bodydst, ".")
if len(ps) == 1 {
dstmap[ps[0]] = bodybuf
} else {
em := make(map[string]interface{})
em[ps[len(ps)-1]] = bodybuf
for i := len(ps) - 2; i > 0; i-- {
nm := make(map[string]interface{})
nm[ps[i]] = em
em = nm
}
dstmap[ps[0]] = em
}
if out, err = jsonpatch.MergeMergePatches(out, bodybuf); err == nil { bodyout, err := json.Marshal(dstmap)
if err != nil {
return nil, err
}
if out, err = jsonpatch.MergeMergePatches(out, bodyout); err == nil {
return out, nil return out, nil
} }

View File

@ -191,6 +191,7 @@ func (r *staticRouter) Endpoint(req *http.Request) (*api.Service, error) {
Host: ep.apiep.Host, Host: ep.apiep.Host,
Method: ep.apiep.Method, Method: ep.apiep.Method,
Path: ep.apiep.Path, Path: ep.apiep.Path,
Body: ep.apiep.Body,
Stream: ep.apiep.Stream, Stream: ep.apiep.Stream,
}, },
Services: services, Services: services,
@ -274,6 +275,7 @@ func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) {
for k, v := range matches { for k, v := range matches {
md[fmt.Sprintf("x-api-field-%s", k)] = v md[fmt.Sprintf("x-api-field-%s", k)] = v
} }
md["x-api-body"] = ep.apiep.Body
*req = *req.Clone(context.WithValue(ctx, metadata.MetadataKey{}, md)) *req = *req.Clone(context.WithValue(ctx, metadata.MetadataKey{}, md))
break pathLoop break pathLoop
} }
@ -285,6 +287,7 @@ func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) {
// we got here, so its a match // we got here, so its a match
return ep, nil return ep, nil
} }
// no match // no match
return nil, fmt.Errorf("endpoint not found for %v", req) return nil, fmt.Errorf("endpoint not found for %v", req)
} }