Skip to content

Commit

Permalink
Adding Object creation/unmarshaling helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
Derek Dowling committed Nov 12, 2015
1 parent 6c44504 commit 4d142c2
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 12 deletions.
50 changes: 47 additions & 3 deletions object.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
package jsh

import (
"encoding/json"
"fmt"
)

// Object represents the default JSON spec for objects
type Object struct {
Type string `json:"type"`
ID string `json:"id"`
Attributes interface{} `json:"attributes"`
Type string `json:"type"`
ID string `json:"id"`
Attributes json.RawMessage `json:"attributes"`
}

// NewObject prepares a new JSON Object for an API response. Whatever is provided
// as attributes will be marshalled to JSON.
func NewObject(id string, objType string, attributes interface{}) (*Object, error) {
object := &Object{
ID: id,
Type: objType,
}

rawJSON, err := json.MarshalIndent(attributes, "", " ")
if err != nil {
return nil, fmt.Errorf("Error marshaling attrs while creating a new JSON Object: %s", err)
}

object.Attributes = rawJSON
return object, nil
}

// Unmarshal puts an Object's Attributes into a more useful target type defined
// by the user. A correct object type specified must also be provided otherwise
// an error is returned to prevent hard to track down situations.
func (o *Object) Unmarshal(objType string, target interface{}) error {

if objType != o.Type {
return fmt.Errorf("Attempting to convert object to incompatible type")
}

err := json.Unmarshal(o.Attributes, target)
if err != nil {
return fmt.Errorf(
"Error converting %s to type '%s': %s",
o.Attributes,
objType,
err.Error(),
)
}

return nil
}
70 changes: 70 additions & 0 deletions object_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package jsh

import (
"encoding/json"
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func TestObject(t *testing.T) {

Convey("Object Tests", t, func() {

testObject := &Object{
ID: "ID123",
Type: "testConversion",
Attributes: json.RawMessage(`{"foo":"bar"}`),
}

Convey("->NewObject()", func() {

Convey("should create a new object with populated attrs", func() {
attrs := struct {
Foo string `json:"foo"`
}{"bar"}

newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
So(err, ShouldBeNil)
So(newObj.Attributes, ShouldNotBeEmpty)
})
})

Convey("->Unmarshal()", func() {
testConversion := struct {
ID string
Foo string `json:"foo"`
}{}

Convey("Should successfully populate a valid struct", func() {
err := testObject.Unmarshal("testConversion", &testConversion)
So(err, ShouldBeNil)
So(testConversion.Foo, ShouldEqual, "bar")
})

Convey("Should reject a non-matching type", func() {
err := testObject.Unmarshal("badType", &testConversion)
So(err, ShouldNotBeNil)
})
})

Convey("->ParseList()", func() {
listJSON :=
`{"data": [
{"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}},
{"type": "user", "id": "sweetID456", "attributes": {"ID":"456"}}
]}`

closer := createIOCloser([]byte(listJSON))

list, err := ParseList(closer)
So(err, ShouldBeNil)
So(len(list), ShouldEqual, 2)

object := list[1]
So(object.Type, ShouldEqual, "user")
So(object.ID, ShouldEqual, "sweetID456")
So(object.Attributes, ShouldResemble, json.RawMessage(`{"ID":"456"}`))
})
})
}
9 changes: 5 additions & 4 deletions parse_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jsh

import (
"encoding/json"
"testing"

. "github.com/smartystreets/goconvey/convey"
Expand All @@ -20,14 +21,14 @@ func TestParsing(t *testing.T) {
So(object, ShouldNotBeEmpty)
So(object.Type, ShouldEqual, "user")
So(object.ID, ShouldEqual, "sweetID123")
So(object.Attributes, ShouldResemble, map[string]interface{}{"ID": "123"})
So(object.Attributes, ShouldResemble, json.RawMessage(`{"ID":"123"}`))
})

Convey("->ParseList()", func() {
listJSON :=
`{"data": [
{"type": "user", "id": "sweetID123", "attributes": {"ID": "123"}},
{"type": "user", "id": "sweetID456", "attributes": {"ID": "456"}}
{"type": "user", "id": "sweetID123", "attributes": {"ID":"123"}},
{"type": "user", "id": "sweetID456", "attributes": {"ID":"456"}}
]}`

closer := createIOCloser([]byte(listJSON))
Expand All @@ -39,7 +40,7 @@ func TestParsing(t *testing.T) {
object := list[1]
So(object.Type, ShouldEqual, "user")
So(object.ID, ShouldEqual, "sweetID456")
So(object.Attributes, ShouldResemble, map[string]interface{}{"ID": "456"})
So(object.Attributes, ShouldResemble, json.RawMessage(`{"ID":"456"}`))
})
})
}
9 changes: 4 additions & 5 deletions send_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jsh

import (
"encoding/json"
"net/http"
"net/http/httptest"
"strconv"
Expand All @@ -17,11 +18,9 @@ func TestSend(t *testing.T) {
request := &http.Request{}

object := &Object{
ID: "1234",
Type: "user",
Attributes: map[string]string{
"foo": "bar",
},
ID: "1234",
Type: "user",
Attributes: json.RawMessage(`{"foo":"bar"}`),
}

Convey("Success Handlers", func() {
Expand Down

0 comments on commit 4d142c2

Please sign in to comment.