diff --git a/list_test.go b/list_test.go index f2f3e39..5bde954 100644 --- a/list_test.go +++ b/list_test.go @@ -35,16 +35,19 @@ func TestList(t *testing.T) { writer := httptest.NewRecorder() err := Send(writer, req, testList) - So(err, ShouldBeNil) So(writer.Code, ShouldEqual, http.StatusOK) + contentLength, convErr := strconv.Atoi(writer.HeaderMap.Get("Content-Length")) So(convErr, ShouldBeNil) So(contentLength, ShouldBeGreaterThan, 0) So(writer.HeaderMap.Get("Content-Type"), ShouldEqual, ContentType) - closer := createIOCloser(writer.Body.Bytes()) - responseList, err := ParseList(closer) + req, reqErr := testRequest(writer.Body.Bytes()) + So(reqErr, ShouldBeNil) + + responseList, err := ParseList(req) + So(err, ShouldBeNil) So(len(responseList), ShouldEqual, 1) }) }) diff --git a/parse.go b/parse.go index 4a4be31..98b0440 100644 --- a/parse.go +++ b/parse.go @@ -6,6 +6,7 @@ import ( "io" "io/ioutil" "log" + "net/http" ) const ( @@ -47,19 +48,18 @@ const ( // http.Error(w, err.Status, err.Detail) // } // } -func ParseObject(reader io.ReadCloser) (*Object, SendableError) { - defer closeReader(reader) +func ParseObject(r *http.Request) (*Object, SendableError) { - byteData, err := ioutil.ReadAll(reader) - if err != nil { - return nil, ISE(fmt.Sprintf("Error attempting to read request body: %s", err)) + byteData, loadErr := loadJSON(r) + if loadErr != nil { + return nil, loadErr } data := struct { Object Object `json:"data"` }{} - err = json.Unmarshal(byteData, &data) + err := json.Unmarshal(byteData, &data) if err != nil { return nil, ISE(fmt.Sprintf("Unable to parse json: \n%s\nError:%s", string(byteData), @@ -73,19 +73,18 @@ func ParseObject(reader io.ReadCloser) (*Object, SendableError) { // ParseList returns a JSON List for a given io.ReadCloser containing // a raw JSON payload -func ParseList(reader io.ReadCloser) ([]*Object, SendableError) { - defer closeReader(reader) +func ParseList(r *http.Request) ([]*Object, SendableError) { - byteData, err := ioutil.ReadAll(reader) - if err != nil { - return nil, ISE(fmt.Sprintf("Error attempting to read request body: %s", err)) + byteData, loadErr := loadJSON(r) + if loadErr != nil { + return nil, loadErr } data := struct { List []*Object `json:"data"` }{List: []*Object{}} - err = json.Unmarshal(byteData, &data) + err := json.Unmarshal(byteData, &data) if err != nil { return nil, ISE(fmt.Sprintf("Unable to parse json: \n%s\nError:%s", string(byteData), @@ -103,9 +102,39 @@ func ParseList(reader io.ReadCloser) ([]*Object, SendableError) { return data.List, nil } +func loadJSON(r *http.Request) ([]byte, SendableError) { + defer closeReader(r.Body) + + validationErr := validateRequest(r) + if validationErr != nil { + return nil, validationErr + } + + byteData, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, ISE(fmt.Sprintf("Error attempting to read request body: %s", err)) + } + + return byteData, nil +} + func closeReader(reader io.ReadCloser) { err := reader.Close() if err != nil { log.Println("Unabled to close request Body") } } + +func validateRequest(r *http.Request) SendableError { + + reqContentType := r.Header.Get("Content-Type") + if reqContentType != ContentType { + return SpecificationError(fmt.Sprintf( + "Expected Content-Type header to be %s, got: %s", + ContentType, + reqContentType, + )) + } + + return nil +} diff --git a/parse_test.go b/parse_test.go index 2e966d9..2042e00 100644 --- a/parse_test.go +++ b/parse_test.go @@ -2,6 +2,7 @@ package jsh import ( "encoding/json" + "net/http" "testing" . "github.com/smartystreets/goconvey/convey" @@ -11,15 +12,38 @@ func TestParsing(t *testing.T) { Convey("Request Tests", t, func() { + Convey("->validateRequest()", func() { + req, err := http.NewRequest("GET", "", nil) + So(err, ShouldBeNil) + req.Header.Set("Content-Type", "jpeg") + + err = validateRequest(req) + So(err, ShouldNotBeNil) + + singleErr := err.(*Error) + So(singleErr.Status, ShouldEqual, http.StatusNotAcceptable) + }) + + Convey("->loadJSON()", func() { + req, err := http.NewRequest("GET", "", createIOCloser([]byte("1234"))) + So(err, ShouldBeNil) + req.Header.Set("Content-Type", ContentType) + + bytes, err := loadJSON(req) + So(err, ShouldBeNil) + So(string(bytes), ShouldEqual, "1234") + }) + Convey("->ParseObject()", func() { Convey("should parse a valid object", func() { objectJSON := `{"data": {"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}}}` - closer := createIOCloser([]byte(objectJSON)) + req, reqErr := testRequest([]byte(objectJSON)) + So(reqErr, ShouldBeNil) - object, err := ParseObject(closer) + object, err := ParseObject(req) So(err, ShouldBeNil) So(object, ShouldNotBeEmpty) So(object.Type, ShouldEqual, "user") @@ -29,9 +53,11 @@ func TestParsing(t *testing.T) { Convey("should reject an object with missing attributes", func() { objectJSON := `{"data": {"id": "sweetID123", "attributes": {"ID":"123"}}}` - closer := createIOCloser([]byte(objectJSON)) - _, err := ParseObject(closer) + req, reqErr := testRequest([]byte(objectJSON)) + So(reqErr, ShouldBeNil) + + _, err := ParseObject(req) So(err, ShouldNotBeNil) vErr, ok := err.(*Error) @@ -50,10 +76,10 @@ func TestParsing(t *testing.T) { {"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}}, {"type": "user", "id": "sweetID456", "attributes": {"ID":"456"}} ]}` + req, reqErr := testRequest([]byte(listJSON)) + So(reqErr, ShouldBeNil) - closer := createIOCloser([]byte(listJSON)) - - list, err := ParseList(closer) + list, err := ParseList(req) So(err, ShouldBeNil) So(len(list), ShouldEqual, 2) @@ -70,9 +96,10 @@ func TestParsing(t *testing.T) { {"type": "user", "attributes": {"ID":"456"}} ]}` - closer := createIOCloser([]byte(listJSON)) + req, reqErr := testRequest([]byte(listJSON)) + So(reqErr, ShouldBeNil) - _, err := ParseList(closer) + _, err := ParseList(req) So(err, ShouldNotBeNil) vErr, ok := err.(*Error) diff --git a/test_util.go b/test_util.go index 0b9fb63..55b2150 100644 --- a/test_util.go +++ b/test_util.go @@ -4,9 +4,20 @@ import ( "bytes" "io" "io/ioutil" + "net/http" ) func createIOCloser(data []byte) io.ReadCloser { reader := bytes.NewReader(data) return ioutil.NopCloser(reader) } + +func testRequest(bytes []byte) (*http.Request, error) { + req, err := http.NewRequest("GET", "", createIOCloser(bytes)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", ContentType) + return req, nil +}