mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
custom Unmarshal JSON
This commit is contained in:
parent
abd696ca56
commit
1be7a42d14
2 changed files with 62 additions and 77 deletions
129
handler.go
129
handler.go
|
|
@ -17,7 +17,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"bytes"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pilosa/pilosa/internal"
|
||||
"github.com/pilosa/pilosa/pql"
|
||||
|
|
@ -322,16 +321,6 @@ type sliceMaxResponse struct {
|
|||
|
||||
// handlePostDB handles POST /db request.
|
||||
func (h *Handler) handlePostDB(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
// Copy request body for validation
|
||||
buf, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
r.Body = rdr2
|
||||
|
||||
// Decode request.
|
||||
var req postDBRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
|
@ -339,15 +328,8 @@ func (h *Handler) handlePostDB(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Validate request
|
||||
err = h.validateRequest(buf, r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Create database.
|
||||
_, err = h.Index.CreateDB(req.DB, req.Options)
|
||||
_, err := h.Index.CreateDB(req.DB, req.Options)
|
||||
if err == ErrDatabaseExists {
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
|
|
@ -362,50 +344,34 @@ func (h *Handler) handlePostDB(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// Validate request body for db/frame creation
|
||||
func (h *Handler) validateRequest(r []byte, path string) error {
|
||||
// Custom Unmarshal JSON to validate request body when creating a new database
|
||||
func (p *postDBRequest) UnmarshalJSON(b []byte) error {
|
||||
var data map[string]interface{}
|
||||
|
||||
err := json.Unmarshal(r, &data)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
option, ok := data["options"]
|
||||
if len(data) >= 2 && !ok {
|
||||
return errors.New("options needs to be provided")
|
||||
} else if ok {
|
||||
err = h.validateOptions(path, option.(map[string]interface{}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid options: %s", option.(map[string]interface{}))
|
||||
}
|
||||
f := func(key string, m map[string]interface{}) bool { _, ok := m[key]; return ok }
|
||||
if !f("db", data) {
|
||||
return errors.New("db required")
|
||||
}
|
||||
p.DB = data["db"].(string)
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Validate options in request body for db/frame creation, make sure key and value for columnLabel/rowLable is correct
|
||||
func (h Handler) validateOptions(path string, options map[string]interface{}) error {
|
||||
switch path {
|
||||
case "/db":
|
||||
if _, ok := options["columnLabel"]; !ok && len(options) > 0 {
|
||||
return errors.New("columnLabel is not provided")
|
||||
} else if ok {
|
||||
if f("options", data) {
|
||||
options := data["options"].(map[string]interface{})
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
} else if f("columnLabel", options) {
|
||||
err := ValidateName(options["columnLabel"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case "/frame":
|
||||
if _, ok := options["rowLabel"]; !ok && len(options) > 0 {
|
||||
return errors.New("rowLabel is not provided")
|
||||
} else if ok {
|
||||
err := ValidateName(options["rowLabel"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New("invalid columnLabel")
|
||||
}
|
||||
p.Options = DBOptions{ColumnLabel: options["columnLabel"].(string)}
|
||||
} else {
|
||||
return errors.New("columnLabel required")
|
||||
}
|
||||
|
||||
} else if len(data) > 1 {
|
||||
return errors.New("options required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -544,22 +510,6 @@ type postDBAttrDiffResponse struct {
|
|||
|
||||
// handlePostFrame handles POST /frame request.
|
||||
func (h *Handler) handlePostFrame(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
// Copy request body for validation
|
||||
buf, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
r.Body = rdr2
|
||||
|
||||
// Validate request
|
||||
err = h.validateRequest(buf, r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Decode request.
|
||||
var req postFrameRequest
|
||||
|
|
@ -576,7 +526,7 @@ func (h *Handler) handlePostFrame(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// Create frame.
|
||||
_, err = db.CreateFrame(req.Frame, req.Options)
|
||||
_, err := db.CreateFrame(req.Frame, req.Options)
|
||||
if err == ErrFrameExists {
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
|
|
@ -591,6 +541,43 @@ func (h *Handler) handlePostFrame(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// Custom Unmarshal JSON to validate request body when creating a new frame
|
||||
func (p *postFrameRequest) UnmarshalJSON(b []byte) error {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
f := func(key string, m map[string]interface{}) bool { _, ok := m[key]; return ok }
|
||||
if !f("db", data) {
|
||||
return errors.New("db required")
|
||||
}
|
||||
p.DB = data["db"].(string)
|
||||
|
||||
if !f("frame", data) {
|
||||
return errors.New("frame required")
|
||||
}
|
||||
p.Frame = data["frame"].(string)
|
||||
|
||||
if f("options", data) {
|
||||
options := data["options"].(map[string]interface{})
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
} else if f("rowLabel", options) {
|
||||
err := ValidateName(options["rowLabel"].(string))
|
||||
if err != nil {
|
||||
return errors.New("invalid rowLabel")
|
||||
}
|
||||
p.Options = FrameOptions{RowLabel: options["rowLabel"].(string)}
|
||||
} else {
|
||||
return errors.New("rowLabel required")
|
||||
}
|
||||
|
||||
} else if len(data) > 2 {
|
||||
return errors.New("options required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type postFrameRequest struct {
|
||||
DB string `json:"db"`
|
||||
Frame string `json:"frame"`
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pilosa/pilosa"
|
||||
"github.com/pilosa/pilosa/internal"
|
||||
|
|
@ -890,8 +889,7 @@ func TestHandler_DB_Options(t *testing.T) {
|
|||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "options needs to be provided"+"\n" {
|
||||
fmt.Println(string(buf) == "options needs to be provided")
|
||||
} else if string(buf) != "options required"+"\n" {
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
|
||||
|
|
@ -921,7 +919,7 @@ func TestHandler_Frame_Options(t *testing.T) {
|
|||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "invalid options: map[columnLabel:location]"+"\n" {
|
||||
} else if string(buf) != "rowLabel required"+"\n" {
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
}
|
||||
|
|
@ -939,7 +937,7 @@ func TestHandler_OptionsValue(t *testing.T) {
|
|||
if _, err := idx.CreateDBIfNotExists("sample-db", pilosa.DBOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/frame", strings.NewReader(`{"db": "sample-db", "options": {"rowLabel": "///"}}`)))
|
||||
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/frame", strings.NewReader(`{"db": "sample-db", "frame": "test", "options": {"rowLabel": "///"}}`)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -950,7 +948,7 @@ func TestHandler_OptionsValue(t *testing.T) {
|
|||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "invalid options: map[rowLabel:///]"+"\n" {
|
||||
} else if string(buf) != "invalid rowLabel"+"\n" {
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue