Skip to content

Commit 32a89e7

Browse files
author
Derek Dowling
committed
Updating terminology, working parse tests
1 parent e8d4a65 commit 32a89e7

File tree

6 files changed

+198
-99
lines changed

6 files changed

+198
-99
lines changed

request.go renamed to parse.go

+17-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package japi
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"io"
67
"io/ioutil"
78
)
@@ -21,16 +22,19 @@ func ParseObject(reader io.ReadCloser) (*Object, error) {
2122
return nil, err
2223
}
2324

24-
request := struct {
25-
Object *Object `json:"data"`
25+
data := struct {
26+
Object Object `json:"data"`
2627
}{}
2728

28-
err = json.Unmarshal(byteData, request)
29+
err = json.Unmarshal(byteData, &data)
2930
if err != nil {
30-
return nil, err
31+
return nil, fmt.Errorf("Unable to parse json: \n%s\nError:%s",
32+
string(byteData),
33+
err.Error(),
34+
)
3135
}
3236

33-
return request.Object, nil
37+
return &data.Object, nil
3438
}
3539

3640
// ParseList returns a JSON List for a given io.ReadCloser containing
@@ -43,14 +47,17 @@ func ParseList(reader io.ReadCloser) ([]*Object, error) {
4347
return nil, err
4448
}
4549

46-
request := struct {
50+
data := struct {
4751
List []*Object `json:"data"`
48-
}{}
52+
}{List: []*Object{}}
4953

50-
err = json.Unmarshal(byteData, request)
54+
err = json.Unmarshal(byteData, &data)
5155
if err != nil {
52-
return nil, err
56+
return nil, fmt.Errorf("Unable to parse json: \n%s\nError:%s",
57+
string(byteData),
58+
err.Error(),
59+
)
5360
}
5461

55-
return request.List, nil
62+
return data.List, nil
5663
}

parse_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package japi
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"io/ioutil"
7+
"testing"
8+
9+
. "github.com/smartystreets/goconvey/convey"
10+
)
11+
12+
func TestRequest(t *testing.T) {
13+
14+
Convey("Request Tests", t, func() {
15+
16+
Convey("->ParseObject()", func() {
17+
objectJSON := `{"data": {"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}}}`
18+
19+
closer := createIOCloser([]byte(objectJSON))
20+
21+
object, err := ParseObject(closer)
22+
So(err, ShouldBeNil)
23+
So(object, ShouldNotBeEmpty)
24+
So(object.Type, ShouldEqual, "user")
25+
So(object.ID, ShouldEqual, "sweetID123")
26+
So(object.Attributes, ShouldResemble, map[string]interface{}{"ID": "123"})
27+
})
28+
29+
Convey("->ParseList()", func() {
30+
listJSON :=
31+
`{"data": [
32+
{"type": "user", "id": "sweetID123", "attributes": {"ID": "123"}},
33+
{"type": "user", "id": "sweetID456", "attributes": {"ID": "456"}}
34+
]}`
35+
36+
closer := createIOCloser([]byte(listJSON))
37+
38+
list, err := ParseList(closer)
39+
So(err, ShouldBeNil)
40+
So(len(list), ShouldEqual, 2)
41+
42+
object := list[1]
43+
So(object.Type, ShouldEqual, "user")
44+
So(object.ID, ShouldEqual, "sweetID456")
45+
So(object.Attributes, ShouldResemble, map[string]interface{}{"ID": "456"})
46+
})
47+
})
48+
}
49+
50+
func createIOCloser(data []byte) io.ReadCloser {
51+
reader := bytes.NewReader(data)
52+
return ioutil.NopCloser(reader)
53+
}

request_test.go

+23-5
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,41 @@ import (
99
. "github.com/smartystreets/goconvey/convey"
1010
)
1111

12-
func TestRequest(t *testing.T) {
12+
func TestParsing(t *testing.T) {
1313

14-
Convey("Request Tests", t, func() {
14+
Convey("Parse Tests", t, func() {
1515

1616
Convey("->ParseObject()", func() {
17-
jsonStr := `{"data": {"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}}}`
17+
objectJSON := `{"data": {"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}}}`
1818

19-
closer := createIOCloser([]byte(jsonStr))
19+
closer := createIOCloser([]byte(objectJSON))
2020

2121
object, err := ParseObject(closer)
2222
So(err, ShouldBeNil)
2323
So(object, ShouldNotBeEmpty)
24-
So(err, ShouldBeNil)
2524
So(object.Type, ShouldEqual, "user")
2625
So(object.ID, ShouldEqual, "sweetID123")
2726
So(object.Attributes, ShouldResemble, map[string]interface{}{"ID": "123"})
2827
})
28+
29+
Convey("->ParseList()", func() {
30+
listJSON :=
31+
`{"data": [
32+
{"type": "user", "id": "sweetID123", "attributes": {"ID": "123"}},
33+
{"type": "user", "id": "sweetID456", "attributes": {"ID": "456"}}
34+
]}`
35+
36+
closer := createIOCloser([]byte(listJSON))
37+
38+
list, err := ParseList(closer)
39+
So(err, ShouldBeNil)
40+
So(len(list), ShouldEqual, 2)
41+
42+
object := list[1]
43+
So(object.Type, ShouldEqual, "user")
44+
So(object.ID, ShouldEqual, "sweetID456")
45+
So(object.Attributes, ShouldResemble, map[string]interface{}{"ID": "456"})
46+
})
2947
})
3048
}
3149

response.go

-84
This file was deleted.

send.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package japi
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"strconv"
8+
)
9+
10+
// Data represents the top level json format of incoming requests
11+
// and outgoing responses
12+
type Data struct {
13+
Data interface{} `json:"data"`
14+
}
15+
16+
// ErrorResponse for API requests
17+
type ErrorResponse struct {
18+
Errors []*Error `json:"errors"`
19+
}
20+
21+
// SendObject sends a single data object as a JSON response
22+
func SendObject(w http.ResponseWriter, status int, object *Object) error {
23+
return Send(w, status, prepareObject(object))
24+
}
25+
26+
// SendList sends a list of data objects as a JSON response
27+
func SendList(w http.ResponseWriter, status int, list []*Object) error {
28+
return Send(w, status, prepareList(list))
29+
}
30+
31+
// SendError is a convenience function that puts an error into an array
32+
// and then calls SendErrors which is the correct error response format
33+
func SendError(w http.ResponseWriter, err *Error) error {
34+
return SendErrors(w, prepareError(err))
35+
}
36+
37+
// SendErrors sends the expected error response format for a
38+
// request that cannot be fulfilled in someway. Allows the user
39+
// to compile multiple errors that can be sent back to a user. Uses
40+
// the first error status as the HTTP Status to return.
41+
func SendErrors(w http.ResponseWriter, errors []*Error) error {
42+
43+
if len(errors) == 0 {
44+
return fmt.Errorf("No errors provided for attempted error response.")
45+
}
46+
47+
// use the first error to set the error status
48+
status := errors[0].Status
49+
return Send(w, status, prepareErrorList(errors))
50+
}
51+
52+
// Send formats a JSON response with the appropriate headers.
53+
func Send(w http.ResponseWriter, status int, payload interface{}) error {
54+
content, err := json.MarshalIndent(payload, "", " ")
55+
if err != nil {
56+
return err
57+
}
58+
59+
w.Header().Add("Content-Type", ContentType)
60+
w.Header().Set("Content-Length", strconv.Itoa(len(content)))
61+
w.WriteHeader(status)
62+
w.Write(content)
63+
64+
return nil
65+
}
66+
67+
func prepareError(err *Error) []*Error {
68+
return []*Error{err}
69+
}
70+
71+
func prepareErrorList(errors []*Error) *ErrorResponse {
72+
return &ErrorResponse{Errors: errors}
73+
}
74+
75+
func prepareObject(object *Object) *Data {
76+
return &Data{Data: object}
77+
}
78+
79+
func prepareList(list []*Object) *Data {
80+
return &Data{Data: list}
81+
}

send_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package japi
2+
3+
import (
4+
"net/http/httptest"
5+
"testing"
6+
7+
. "github.com/smartystreets/goconvey/convey"
8+
)
9+
10+
func TestSend(t *testing.T) {
11+
12+
Convey("Send Tests", t, func() {
13+
14+
response := httptest.NewRecorder()
15+
16+
Convey("->SendObject()", func() {
17+
18+
})
19+
20+
Convey("->SendList()", func() {
21+
22+
})
23+
})
24+
}

0 commit comments

Comments
 (0)