diff --git a/README.md b/README.md index 2182632..6aa4ddf 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ GET https://api.example.com/v1/foos/1?select=foo {"foo":1} ``` +dynjson mimicks the original struct using the original types and json tags. +The field order is the same as the select parameters. + ## Installation go get github.com/cocoonspace/dynjson @@ -33,13 +36,37 @@ type APIResult struct { f := dynjson.NewFormatter() res := &APIResult{Foo:1, Bar:"bar"} -o, err := f.Format(res, []string{"foo"}, nil) +o, err := f.Format(res, dynjson.FieldsFromRequest(r)) if err != nil { // handle error } err := json.Marshal(w, o) // {"foo": 1} ``` +With struct fields : + + +```go +type APIResult struct { + Foo int `json:"foo"` + Bar APIIncluded `json:"bar"` +} + +type APIIncluded struct { + BarFoo int `json:"barfoo"` + BarBar string `json:"barbar"` +} + +f := dynjson.NewFormatter() + +res := &APIResult{Foo: 1, Bar: APIIncluded{BarFoo:1, BarBar: "bar"}} +o, err := f.Format(res, []string{"foo", "bar.barfoo"}) +if err != nil { + // handle error +} +err := json.Marshal(w, o) // {"foo": 1, "bar":{"barfoo": 1}} +``` + With slices: ```go @@ -50,8 +77,8 @@ type APIResult struct { f := dynjson.NewFormatter() -res := []APIResult{{Foo:1, Bar:"bar"}} -o, err := f.Format(res, []string{"foo"}, nil) +res := []APIResult{{Foo: 1, Bar: "bar"}} +o, err := f.Format(res, []string{"foo"}) if err != nil { // handle error } @@ -72,8 +99,8 @@ type APIItem struct { f := dynjson.NewFormatter() -res := &APIResult{Foo:1, Bar:[]APIItem{{BarFoo:1, BarBar: "bar"}}} -o, err := f.Format(res, []string{"foo", "bar.barfoo"}, nil) +res := &APIResult{Foo: 1, Bar: []APIItem{{BarFoo: 1, BarBar: "bar"}}} +o, err := f.Format(res, []string{"foo", "bar.barfoo"}) if err != nil { // handle error } diff --git a/request.go b/request.go new file mode 100644 index 0000000..b0214bf --- /dev/null +++ b/request.go @@ -0,0 +1,30 @@ +package dynjson + +import ( + "net/http" + "net/url" + "strings" +) + +type Option int + +const ( + OptionMultipleFields Option = iota + OptionCommaList +) + +// FieldsFromRequest returns the list of fields requested from a http.Request +// Without opt or with OptionMultipleFields, the expected format is: +// http://api.example.com/endpoint?select=foo&select=bar +// With OptionCommaList, the expected format is: +// http://api.example.com/endpoint?select=foo,bar +func FieldsFromRequest(r *http.Request, opt ...Option) []string { + vals, err := url.ParseQuery(r.URL.RawQuery) + if err != nil { + return nil + } + if len(opt) == 1 && opt[0] == OptionCommaList && len(vals["select"]) > 0 { + return strings.Split(vals["select"][0], ",") + } + return vals["select"] +} diff --git a/request_test.go b/request_test.go new file mode 100644 index 0000000..ceeeb57 --- /dev/null +++ b/request_test.go @@ -0,0 +1,49 @@ +package dynjson + +import ( + "net/http" + "testing" +) + +func TestFieldsFromRequest(t *testing.T) { + { + r, err := http.NewRequest(http.MethodGet, "http://api.example.com/endpoint?select=foo&select=bar", nil) + if err != nil { + t.Error("Should not have returned", err) + } + fields := FieldsFromRequest(r) + if len(fields) != 2 { + t.Error("2 fields were expected") + } + if fields[0] != "foo" || fields[1] != "bar" { + t.Errorf("Expected [foo bar] but got %v", fields) + } + } + { + r, err := http.NewRequest(http.MethodGet, "http://api.example.com/endpoint?select=foo&select=bar", nil) + if err != nil { + t.Error("Should not have returned", err) + } + fields := FieldsFromRequest(r, OptionMultipleFields) + if len(fields) != 2 { + t.Error("2 fields were expected") + } + if fields[0] != "foo" || fields[1] != "bar" { + t.Errorf("Expected [foo bar] but got %v", fields) + } + } + { + r, err := http.NewRequest(http.MethodGet, "http://api.example.com/endpoint?select=foo,bar", nil) + if err != nil { + t.Error("Should not have returned", err) + } + fields := FieldsFromRequest(r, OptionCommaList) + if len(fields) != 2 { + t.Error("2 fields were expected") + } + if fields[0] != "foo" || fields[1] != "bar" { + t.Errorf("Expected [foo bar] but got %v", fields) + } + } + +}