diff --git a/example/example.cabal b/example/example.cabal
--- a/example/example.cabal
+++ b/example/example.cabal
@@ -35,6 +35,7 @@
                , servant-server >= 0.7.1 && < 0.8.0
                , text           >= 1.2.2.1 && < 1.2.3.0
                , url            >= 2.1.3 && < 2.2.0
+               , unordered-containers >= 0.2.7.1 && < 0.2.8.0
                , wai            >= 3.2.1.1 && < 3.2.2.0
                , warp
 
diff --git a/json-api.cabal b/json-api.cabal
--- a/json-api.cabal
+++ b/json-api.cabal
@@ -1,5 +1,5 @@
 name:                json-api
-version:             0.1.0.4
+version:             0.1.1.0
 homepage:            https://github.com/toddmohney/json-api
 bug-reports:         https://github.com/toddmohney/json-api/issues
 license:             MIT
@@ -52,6 +52,7 @@
     RecordWildCards
 
   exposed-modules:
+    Network.JSONApi
     Network.JSONApi.Error
     Network.JSONApi.Document
     Network.JSONApi.Meta
@@ -80,6 +81,7 @@
                , lens         >= 4.13 && < 5.0
                , lens-aeson   >= 1.0.0.5 && < 1.0.1.0
                , text         >= 1.2.2.1 && < 1.2.3.0
+               , unordered-containers >= 0.2.7.1 && < 0.2.8.0
                , url          >= 2.1.3 && < 2.2.0
 
   default-language:    Haskell2010
@@ -94,7 +96,6 @@
     -Wall
     -fwarn-unused-matches
     -fwarn-unused-binds
-    -fwarn-unused-imports
 
   hs-source-dirs: test
 
diff --git a/src/Network/JSONApi.hs b/src/Network/JSONApi.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/JSONApi.hs
@@ -0,0 +1,28 @@
+{- |
+Entry-point module for this package.
+
+Contains representations of the top-level JSON-API document structure.
+-}
+module Network.JSONApi
+  ( D.Document
+  , D.ErrorDocument (..)
+  , E.Error (..)
+  , D.ResourceData (..)
+  , R.Relationship
+  , R.Resource (..)
+  , R.ResourcefulEntity (..)
+  , R.Identifier (..)
+  , L.Links
+  , M.Meta (..)
+  , M.MetaObject (..)
+  , L.toLinks
+  , R.mkRelationship
+  , D.mkDocument
+  , M.mkMeta
+  ) where
+
+import qualified Network.JSONApi.Error as E
+import qualified Network.JSONApi.Document as D
+import qualified Network.JSONApi.Link as L
+import qualified Network.JSONApi.Meta as M
+import qualified Network.JSONApi.Resource as R
diff --git a/src/Network/JSONApi/Document.hs b/src/Network/JSONApi/Document.hs
--- a/src/Network/JSONApi/Document.hs
+++ b/src/Network/JSONApi/Document.hs
@@ -4,23 +4,17 @@
 Contains representations of the top-level JSON-API document structure.
 -}
 module Network.JSONApi.Document
-( Document (..)
+( Document
 , ErrorDocument (..)
-, E.Error (..)
 , ResourceData (..)
-, R.Relationship
-, R.Resource (..)
-, R.Identifier (..)
-, L.Links
-, M.Meta (..)
-, L.toLinks
-, R.mkRelationship
+, mkDocument
 ) where
 
 import Control.Monad (mzero)
 import Data.Aeson
   ( ToJSON
   , FromJSON
+  , Value
   , (.=)
   , (.:)
   , (.:?)
@@ -30,7 +24,7 @@
 import qualified Network.JSONApi.Error as E
 import Network.JSONApi.Link as L
 import Network.JSONApi.Meta as M
-import Network.JSONApi.Resource (Resource)
+import Network.JSONApi.Resource (Resource, ResourcefulEntity)
 import qualified Network.JSONApi.Resource as R
 
 {- |
@@ -41,13 +35,58 @@
 
 For more information see: <http://jsonapi.org/format/#document-top-level>
 -}
-data Document a b c = Document
-  { _data  ::  ResourceData a b
+data Document a = Document
+  { _data  ::  ResourceData a
   , _links ::  Maybe Links
-  , _meta  ::  Maybe (Meta c)
+  , _meta  ::  Maybe Meta
+  , _included :: [Value]
   } deriving (Show, Eq, G.Generic)
 
+instance (ToJSON a)
+      => ToJSON (Document a) where
+  toJSON (Document (List res) links meta included) =
+    AE.object [ "data"  .= res
+              , "links" .= links
+              , "meta"  .= meta
+              , "included" .= included
+              ]
+  toJSON (Document (Singleton res) links meta included) =
+    AE.object [ "data"  .= res
+              , "links" .= links
+              , "meta"  .= meta
+              , "included" .= included
+              ]
+
+instance (FromJSON a) => FromJSON (Document a) where
+  parseJSON = AE.withObject "document" $ \v -> do
+    d <- v .:  "data"
+    l <- v .:? "links"
+    m <- v .:? "meta"
+    i <- v .: "included"
+    return (Document d l m i)
+
 {- |
+Constructor function for the Document data type.
+-}
+mkDocument :: ResourcefulEntity a =>
+              [a]
+           -> Maybe Links
+           -> Maybe Meta
+           -> [Value]
+           -> Document a
+mkDocument res links meta included =
+  Document
+    { _data = toResourceData res
+    , _links = links
+    , _meta = meta
+    , _included = included
+    }
+
+toResourceData :: ResourcefulEntity a => [a] -> ResourceData a
+toResourceData (r:[]) = Singleton (R.toResource r)
+toResourceData rs      = List (map R.toResource rs)
+
+{- |
 The @Resource@ type encapsulates the underlying 'Resource'
 
 Included in the top-level 'Document', the @Resource@ may be either
@@ -55,38 +94,19 @@
 
 For more information see: <http://jsonapi.org/format/#document-top-level>
 -}
-data ResourceData a b = Singleton (Resource a b)
-                      | List [Resource a b]
+data ResourceData a = Singleton (Resource a)
+                      | List [ Resource a ]
                       deriving (Show, Eq, G.Generic)
 
-instance (ToJSON a, ToJSON b) => ToJSON (ResourceData a b) where
+instance (ToJSON a) => ToJSON (ResourceData a) where
   toJSON (Singleton res) = AE.toJSON res
   toJSON (List res)      = AE.toJSON res
 
-instance (FromJSON a, FromJSON b) => FromJSON (ResourceData a b) where
+instance (FromJSON a) => FromJSON (ResourceData a) where
   parseJSON (AE.Object v) = Singleton <$> (AE.parseJSON (AE.Object v))
   parseJSON (AE.Array v)  = List <$> (AE.parseJSON (AE.Array v))
   parseJSON _             = mzero
 
-instance (ToJSON a, ToJSON b, ToJSON c) => ToJSON (Document a b c) where
-  toJSON (Document (List res) links meta) =
-    AE.object [ "data"  .= res
-              , "links" .= links
-              , "meta"  .= meta
-              ]
-  toJSON (Document (Singleton res) links meta) =
-    AE.object [ "data"  .= res
-              , "links" .= links
-              , "meta"  .= meta
-              ]
-
-instance (FromJSON a, FromJSON b, FromJSON c) => FromJSON (Document a b c) where
-  parseJSON = AE.withObject "document" $ \v -> do
-    d <- v .:  "data"
-    l <- v .:? "links"
-    m <- v .:? "meta"
-    return (Document d l m)
-
 {- |
 The @ErrorDocument@ type represents the alternative form of the top-level
 JSON-API requirement.
@@ -96,20 +116,20 @@
 
 For more information see: <http://jsonapi.org/format/#errors>
 -}
-data ErrorDocument a b = ErrorDocument
+data ErrorDocument a = ErrorDocument
   { _error :: E.Error a
   , _errorLinks :: Maybe Links
-  , _errorMeta  :: Maybe (Meta b)
+  , _errorMeta  :: Maybe Meta
   } deriving (Show, Eq, G.Generic)
 
-instance (ToJSON a, ToJSON b) => ToJSON (ErrorDocument a b) where
+instance (ToJSON a) => ToJSON (ErrorDocument a) where
   toJSON (ErrorDocument err links meta) =
     AE.object [ "error" .= err
               , "links" .= links
               , "meta"  .= meta
               ]
 
-instance (FromJSON a, FromJSON b) => FromJSON (ErrorDocument a b) where
+instance (FromJSON a) => FromJSON (ErrorDocument a) where
   parseJSON = AE.withObject "error" $ \v ->
     ErrorDocument
       <$> v .: "error"
diff --git a/src/Network/JSONApi/Error.hs b/src/Network/JSONApi/Error.hs
--- a/src/Network/JSONApi/Error.hs
+++ b/src/Network/JSONApi/Error.hs
@@ -31,7 +31,7 @@
         , code   :: Maybe Text
         , title  :: Maybe Text
         , detail :: Maybe Text
-        , meta   :: Maybe (Meta a)
+        , meta   :: Maybe Meta
         }
   deriving (Show, Eq, G.Generic)
 
diff --git a/src/Network/JSONApi/Meta.hs b/src/Network/JSONApi/Meta.hs
--- a/src/Network/JSONApi/Meta.hs
+++ b/src/Network/JSONApi/Meta.hs
@@ -3,10 +3,14 @@
 
 Specification: <http://jsonapi.org/format/#document-meta>
 -}
-module Network.JSONApi.Meta where
+module Network.JSONApi.Meta
+( Meta (..)
+, MetaObject (..)
+, mkMeta
+)where
 
-import Data.Aeson (ToJSON, FromJSON)
-import Data.Map (Map)
+import Data.Aeson (ToJSON, FromJSON, Object, toJSON)
+import Data.HashMap.Strict as HM
 import Data.Text (Text)
 import qualified GHC.Generics as G
 
@@ -31,8 +35,41 @@
 
 Specification: <http://jsonapi.org/format/#document-meta>
 -}
-data Meta a = Meta (Map Text a)
-  deriving (Show, Eq, Ord, G.Generic)
+data Meta = Meta Object
+  deriving (Show, Eq, G.Generic)
 
-instance ToJSON a   => ToJSON (Meta a)
-instance FromJSON a => FromJSON (Meta a)
+instance ToJSON Meta
+instance FromJSON Meta
+
+instance Monoid Meta where
+  mappend (Meta a) (Meta b) = Meta $ HM.union a b
+  mempty = Meta $ HM.empty
+
+{- |
+Convienience class for constructing a Meta type
+
+Example usage:
+@
+data Pagination = Pagination
+  { currentPage :: Int
+  , totalPages :: Int
+  } deriving (Show, Generic)
+
+instance ToJSON Pagination
+instance MetaObject Pagination where
+  typeName _ = "pagination"
+@
+-}
+class (ToJSON a) => MetaObject a where
+  typeName :: a -> Text
+
+{- |
+Convienience constructor function for the Meta type
+
+Useful on its own or in combination with Meta's monoid instance
+
+Example usage:
+See MetaSpec.hs for an example
+-}
+mkMeta :: (MetaObject a) => a -> Meta
+mkMeta obj = Meta $ HM.singleton (typeName obj) (toJSON obj)
diff --git a/src/Network/JSONApi/Resource.hs b/src/Network/JSONApi/Resource.hs
--- a/src/Network/JSONApi/Resource.hs
+++ b/src/Network/JSONApi/Resource.hs
@@ -6,6 +6,7 @@
 module Network.JSONApi.Resource
 ( Identifier (..)
 , Resource (..)
+, ResourcefulEntity (..)
 , Relationship
 , mkRelationship
 ) where
@@ -28,15 +29,15 @@
 
 Specification: <http://jsonapi.org/format/#document-resource-objects>
 -}
-data Resource a b = Resource
+data Resource a = Resource
   { getIdentifier :: Identifier
   , getResource :: a
   , getLinks :: Maybe Links
-  , getMetaData :: Maybe (Meta b)
+  , getMetaData :: Maybe Meta
   , getRelationships :: Maybe (Map Text Relationship)
   } deriving (Show, Eq, G.Generic)
 
-instance (ToJSON a, ToJSON b) => ToJSON (Resource a b) where
+instance (ToJSON a) => ToJSON (Resource a) where
   toJSON (Resource (Identifier resId resType) resObj linksObj metaObj rels) =
     AE.object [ "id"            .= resId
               , "type"          .= resType
@@ -46,7 +47,7 @@
               , "relationships" .= rels
               ]
 
-instance (FromJSON a, FromJSON b) => FromJSON (Resource a b) where
+instance (FromJSON a) => FromJSON (Resource a) where
   parseJSON = AE.withObject "resourceObject" $ \v -> do
     id    <- v .: "id"
     typ   <- v .: "type"
@@ -56,8 +57,27 @@
     rels  <- v .:? "relationships"
     return $ Resource (Identifier id typ) attrs links meta rels
 
+{- |
+A typeclass for decorating an entity with JSON API properties
+-}
+class (ToJSON a, FromJSON a) => ResourcefulEntity a where
+  resourceIdentifier :: a -> Text
+  resourceType :: a -> Text
+  resourceLinks :: a -> Maybe Links
+  resourceMetaData :: a -> Maybe Meta
+  resourceRelationships :: a -> Maybe (Map Text Relationship)
 
+  fromResource :: Resource a -> a
+  fromResource = getResource
 
+  toResource :: a -> Resource a
+  toResource a =
+    Resource
+      (Identifier (resourceIdentifier a) (resourceType a))
+      a
+      (resourceLinks a)
+      (resourceMetaData a)
+      (resourceRelationships a)
 
 {- |
 A type representing the Relationship between 2 entities
@@ -88,8 +108,6 @@
 mkRelationship :: Maybe Identifier -> Maybe Links -> Maybe Relationship
 mkRelationship Nothing Nothing = Nothing
 mkRelationship resId links = Just $ Relationship resId links
-
-
 
 {- |
 Identifiers are used to encapsulate the minimum amount of information
diff --git a/test/Network/JSONApi/DocumentSpec.hs b/test/Network/JSONApi/DocumentSpec.hs
--- a/test/Network/JSONApi/DocumentSpec.hs
+++ b/test/Network/JSONApi/DocumentSpec.hs
@@ -1,16 +1,16 @@
 module Network.JSONApi.DocumentSpec where
 
-import           Control.Lens ((^?))
-import           Data.Aeson (ToJSON)
+import Control.Lens ((^?))
+import Data.Aeson (ToJSON)
 import qualified Data.Aeson as AE
 import qualified Data.Aeson.Lens as Lens
-import           Data.ByteString.Lazy.Char8 (ByteString)
+import Data.ByteString.Lazy.Char8 (ByteString)
 {- import qualified Data.ByteString.Lazy.Char8 as BS -}
-import           Data.Either (isRight)
-import           Data.Maybe
-import           Network.JSONApi.Document
-import           TestHelpers
-import           Test.Hspec
+import Data.Either (isRight)
+import Data.Maybe
+import Network.JSONApi.Document
+import TestHelpers
+import Test.Hspec
 
 main :: IO ()
 main = hspec spec
@@ -19,8 +19,8 @@
 spec =
   describe "JSON serialization" $ do
     it "JSON encodes/decodes a singleton resource" $ do
-      let resource = toResource testObject
-      let jsonApiObj = Document (Singleton resource) emptyLinks emptyMeta
+      -- TODO: test the main resource actually is a singleton
+      let jsonApiObj = mkDocument [testObject] Nothing Nothing []
       let encodedJson = encodeDocumentObject jsonApiObj
       let decodedJson = decodeDocumentObject encodedJson
       {- putStrLn (BS.unpack encodedJson) -}
@@ -28,8 +28,8 @@
       isRight decodedJson `shouldBe` True
 
     it "JSON encodes/decodes a list of resources" $ do
-      let resources = [toResource testObject, toResource testObject2]
-      let jsonApiObj = Document (List resources) emptyLinks emptyMeta
+      -- TODO: test the main resource actually is a list
+      let jsonApiObj = mkDocument [testObject, testObject2] Nothing Nothing []
       let encodedJson = encodeDocumentObject jsonApiObj
       let decodedJson = decodeDocumentObject encodedJson
       {- putStrLn (BS.unpack encodedJson) -}
@@ -37,47 +37,44 @@
       isRight decodedJson `shouldBe` True
 
     it "contains the allowable top-level keys" $ do
-      let resource = toResource testObject
-      let jsonApiObj = Document (Singleton resource) emptyLinks emptyMeta
+      let jsonApiObj = mkDocument [testObject] Nothing Nothing []
       let encodedJson = encodeDocumentObject jsonApiObj
       let dataObject = encodedJson ^? Lens.key "data"
       let linksObject = encodedJson ^? Lens.key "links"
       let metaObject = encodedJson ^? Lens.key "meta"
+      let includedObject = encodedJson ^? Lens.key "included"
       isJust dataObject `shouldBe` True
       isJust linksObject `shouldBe` True
       isJust metaObject `shouldBe` True
+      isJust includedObject `shouldBe` True
 
     it "allows an optional top-level links object" $ do
-      let resource = toResource testObject
-      let jsonApiObj = Document (Singleton resource) (Just linksObj) emptyMeta
+      let jsonApiObj = mkDocument [testObject] (Just linksObj) Nothing []
       let encodedJson = encodeDocumentObject jsonApiObj
       let decodedJson = decodeDocumentObject encodedJson
       -- putStrLn (BS.unpack encodedJson)
-      -- putStrLn $ show . fromJust $ decodedJson
+      -- putStrLn $ show decodedJson
       isRight decodedJson `shouldBe` True
 
     it "allows an optional top-level meta object" $ do
-      let resource = toResource testObject
-      let jsonApiObj = Document (Singleton resource) emptyLinks (Just testMetaObj)
+      let jsonApiObj = mkDocument [testObject] Nothing (Just testMetaObj) []
       let encodedJson = encodeDocumentObject jsonApiObj
       let decodedJson = decodeDocumentObject encodedJson
       -- putStrLn (BS.unpack encodedJson)
-      -- putStrLn $ show . fromJust $ decodedJson
+      -- putStrLn $ show decodedJson
       isRight decodedJson `shouldBe` True
 
-    it "allows an optional top-level meta object" $ do
-      let resource = toResource testObject
-      let jsonApiObj = Document (Singleton resource) (Just linksObj) (Just testMetaObj)
+    it "allows a heterogeneous list of related resources" $ do
+      let jsonApiObj = mkDocument [testObject] Nothing Nothing [AE.toJSON (toResource' testObject Nothing Nothing), AE.toJSON (toResource' otherTestObject Nothing Nothing)]
       let encodedJson = encodeDocumentObject jsonApiObj
       let decodedJson = decodeDocumentObject encodedJson
-      -- putStrLn (BS.unpack encodedJson)
-      -- putStrLn $ show . fromJust $ decodedJson
+      {- putStrLn (BS.unpack encodedJson) -}
+      {- putStrLn $ show decodedJson -}
       isRight decodedJson `shouldBe` True
 
 decodeDocumentObject :: ByteString
-                    -> Either String (Document TestResource (Maybe Bool) (Maybe TestMetaObject))
+                    -> Either String (Document TestResource)
 decodeDocumentObject = AE.eitherDecode
 
-encodeDocumentObject :: (ToJSON a, ToJSON b, ToJSON c) => Document a b c -> ByteString
+encodeDocumentObject :: (ToJSON a) => Document a -> ByteString
 encodeDocumentObject = prettyEncode
-
diff --git a/test/Network/JSONApi/ErrorSpec.hs b/test/Network/JSONApi/ErrorSpec.hs
--- a/test/Network/JSONApi/ErrorSpec.hs
+++ b/test/Network/JSONApi/ErrorSpec.hs
@@ -13,7 +13,7 @@
 main = hspec spec
 
 spec :: Spec
-spec =
+spec = do
   describe "Defaults" $ do
     it "provides defaults" $
       let expectedDefault = Error
@@ -27,6 +27,7 @@
             }
       in (def::Error Int) `shouldBe` expectedDefault
 
+  describe "JSON serialization" $
     it "provides ToJSON/FromJSON instances" $ do
       let testError = (def::Error Int)
       let encJson = BS.unpack . prettyEncode $ testError
diff --git a/test/Network/JSONApi/MetaSpec.hs b/test/Network/JSONApi/MetaSpec.hs
--- a/test/Network/JSONApi/MetaSpec.hs
+++ b/test/Network/JSONApi/MetaSpec.hs
@@ -1,9 +1,13 @@
 module Network.JSONApi.MetaSpec where
 
+import           Data.Aeson (ToJSON)
 import qualified Data.Aeson as AE
 import qualified Data.ByteString.Lazy.Char8 as BS
-import qualified Data.Map as Map
+import qualified Data.HashMap.Strict as HM
 import           Data.Maybe (isJust)
+import           Data.Monoid ((<>))
+import           Data.Text (Text)
+import           GHC.Generics (Generic)
 import           Network.JSONApi.Meta
 import           TestHelpers (prettyEncode)
 import           Test.Hspec
@@ -12,22 +16,55 @@
 main = hspec spec
 
 spec :: Spec
-spec =
-  describe "serialization" $
-    -- is there a compelling reason to test this?
-    --
-    it "serializes/deserializes primitive values" $ do
-      let intTestData = Meta . Map.fromList $ [ ("numData", 5 :: Int) ]
-      let encIntJson = BS.unpack . prettyEncode $ intTestData
-      let decIntJson = AE.decode (BS.pack encIntJson) :: Maybe (Meta Int)
+spec = do
+  describe "JSON serialization" $ do
+    it "serializes/deserializes maps simple heterogeneous values" $ do
+      let testMeta = Meta . HM.fromList $ [ ("numData", AE.toJSON (5 :: Int))
+                                          , ("strData", AE.toJSON ("hello" :: String))
+                                          ]
+      let encIntJson = BS.unpack . prettyEncode $ testMeta
+      let decIntJson = AE.decode (BS.pack encIntJson) :: Maybe Meta
       isJust decIntJson `shouldBe` True
-      -- putStrLn (keys encIntJson)
-      -- putStrLn $ show . fromJust $ decIntJson
 
-      let boolTestData = Meta . Map.fromList $ [ ("boolData", True) ]
+    it "serializes/deserializes heterogeneous maps of ToJSON types" $ do
+      let boolTestData = Meta . HM.fromList $ [ ("objData", AE.toJSON testObject)
+                                              , ("otherObjData", AE.toJSON otherTestObject)
+                                              ]
       let encBoolJson = BS.unpack . prettyEncode $ boolTestData
-      let decBoolJson = AE.decode (BS.pack encBoolJson) :: Maybe (Meta Bool)
+      let decBoolJson = AE.decode (BS.pack encBoolJson) :: Maybe Meta
       isJust decBoolJson `shouldBe` True
-      -- putStrLn (keys encBoolJson)
-      -- putStrLn $ show . fromJust $ decBoolJson
 
+  describe "monoid instance" $
+    it "combines" $ do
+      let monoidialConstruction = mkMeta testObject <> mkMeta otherTestObject
+      let manualConstruction = Meta . HM.fromList $ [ ("testObject", AE.toJSON testObject)
+                                                    , ("otherTestObject", AE.toJSON otherTestObject)
+                                                    ]
+      monoidialConstruction `shouldBe` manualConstruction
+
+testObject :: TestObject
+testObject = TestObject 99 102 "Zapp Brannigan"
+
+otherTestObject :: OtherTestObject
+otherTestObject = OtherTestObject "Olive Garden" "Woofers" 29 "TGIFriday's"
+
+data TestObject = TestObject
+  { myID :: Int
+  , myAge :: Int
+  , myName :: Text
+  } deriving (Show, Generic)
+
+instance ToJSON TestObject
+instance MetaObject TestObject where
+  typeName _ = "testObject"
+
+data OtherTestObject = OtherTestObject
+  { myFavoriteRestaurant :: Text
+  , myDogsName :: Text
+  , myDogsAge :: Int
+  , myDogsFavoriteRestarant :: Text
+  } deriving (Show, Generic)
+
+instance ToJSON OtherTestObject
+instance MetaObject OtherTestObject where
+  typeName _ = "otherTestObject"
diff --git a/test/Network/JSONApi/ResourceSpec.hs b/test/Network/JSONApi/ResourceSpec.hs
--- a/test/Network/JSONApi/ResourceSpec.hs
+++ b/test/Network/JSONApi/ResourceSpec.hs
@@ -4,6 +4,7 @@
 import qualified Data.ByteString.Lazy.Char8 as BS
 import Data.Map (Map)
 import qualified Data.Map as Map
+import qualified Data.HashMap.Strict as HM
 import Data.Maybe (isJust, fromJust)
 import Data.Text (Text, pack)
 import qualified GHC.Generics as G
@@ -19,10 +20,10 @@
 
 spec :: Spec
 spec =
-  describe "ToResource" $
+  describe "JSON serialization" $
     it "can be encoded and decoded from JSON" $ do
       let encodedJson = BS.unpack . prettyEncode $ toResource testObject
-      let decodedJson = AE.decode (BS.pack encodedJson) :: Maybe (Resource TestObject (Maybe Int))
+      let decodedJson = AE.decode (BS.pack encodedJson) :: Maybe (Resource TestObject)
       isJust decodedJson `shouldBe` True
       {- putStrLn encodedJson -}
       {- putStrLn $ show . fromJust $ decodedJson -}
@@ -36,33 +37,30 @@
 
 instance AE.ToJSON TestObject
 instance AE.FromJSON TestObject
-
-toResource :: TestObject -> Resource TestObject Int
-toResource obj =
-  Resource
-    (Identifier (pack . show . myId $ obj) "TestObject")
-    obj
-    (Just resourceLinks)
-    (Just resourceMetaData)
-    (Just resourceRelationships)
+instance ResourcefulEntity TestObject where
+  resourceIdentifier = pack . show . myId
+  resourceType _ = "TestObject"
+  resourceLinks _ = Just myResourceLinks
+  resourceMetaData _ = Just myResourceMetaData
+  resourceRelationships _ = Just myResourceRelationships
 
-resourceRelationships :: Map Text Relationship
-resourceRelationships = Map.fromList $ [ ("friends", relationship) ]
+myResourceRelationships :: Map Text Relationship
+myResourceRelationships = Map.fromList $ [ ("friends", relationship) ]
 
 relationship :: Relationship
 relationship =
   fromJust $ mkRelationship
     (Just $ Identifier "42" "FriendOfTestObject")
-    (Just resourceLinks)
+    (Just myResourceLinks)
 
-resourceLinks :: Links
-resourceLinks =
+myResourceLinks :: Links
+myResourceLinks =
   toLinks [ ("self", toURL "/me")
           , ("related", toURL "/tacos/4")
           ]
 
-resourceMetaData :: Meta Int
-resourceMetaData = Meta . Map.fromList $ [ ("extraData", 20) ]
+myResourceMetaData :: Meta
+myResourceMetaData = Meta . HM.fromList $ [ ("extraData", AE.toJSON (20 :: Int)) ]
 
 toURL :: String -> URL
 toURL = fromJust . importURL
diff --git a/test/TestHelpers.hs b/test/TestHelpers.hs
--- a/test/TestHelpers.hs
+++ b/test/TestHelpers.hs
@@ -4,11 +4,10 @@
 import qualified Data.Aeson.Encode.Pretty as AE
 import qualified Data.ByteString.Lazy.Char8 as BS
 import Data.Maybe (fromJust)
-import qualified Data.Map as Map
-import Data.Monoid ((<>))
+import qualified Data.HashMap.Strict as HM
 import Data.Text (Text, pack)
-import qualified GHC.Generics as G
-import Network.JSONApi.Document
+import GHC.Generics (Generic)
+import Network.JSONApi
 import Network.URL (URL, importURL)
 
 prettyEncode :: AE.ToJSON a => a -> BS.ByteString
@@ -17,43 +16,68 @@
 prettyConfig :: AE.Config
 prettyConfig = AE.Config { AE.confIndent = 2, AE.confCompare = mempty }
 
+class HasIdentifiers a where
+  uniqueId :: a -> Int
+  typeDescriptor :: a -> Text
+
 data TestResource = TestResource
   { myId :: Int
   , myName :: Text
   , myAge :: Int
   , myFavoriteFood :: Text
-  } deriving (Show, G.Generic)
+  } deriving (Show, Generic)
 
+instance AE.ToJSON TestResource
+instance AE.FromJSON TestResource
+instance ResourcefulEntity TestResource where
+  resourceIdentifier = pack . show . myId
+  resourceType _ = "testResource"
+  resourceLinks _ = Nothing
+  resourceMetaData _ = Nothing
+  resourceRelationships _ = Nothing
+instance HasIdentifiers TestResource where
+  uniqueId = myId
+  typeDescriptor _ = "TestResource"
+
+data OtherTestResource = OtherTestResource
+  { myFavoriteNumber :: Int
+  , myJob :: Text
+  , myPay :: Int
+  , myEmployer :: Text
+  } deriving (Show, Generic)
+
+instance AE.ToJSON OtherTestResource
+instance AE.FromJSON OtherTestResource
+instance ResourcefulEntity OtherTestResource where
+  resourceIdentifier = pack . show . myFavoriteNumber
+  resourceType _ = "otherTestResource"
+  resourceLinks _ = Nothing
+  resourceMetaData _ = Nothing
+  resourceRelationships _ = Nothing
+instance HasIdentifiers OtherTestResource where
+  uniqueId = myFavoriteNumber
+  typeDescriptor _ = "OtherTestResource"
+
 data TestMetaObject = TestMetaObject
   { totalPages :: Int
   , isSuperFun :: Bool
-  } deriving (Show, G.Generic)
-
-instance AE.ToJSON TestResource
-instance AE.FromJSON TestResource
+  } deriving (Show, Generic)
 
 instance AE.ToJSON TestMetaObject
 instance AE.FromJSON TestMetaObject
 
-toResource :: TestResource -> Resource TestResource Bool
-toResource obj =
+toResource' :: (HasIdentifiers a) => a
+            -> Maybe Links
+            -> Maybe Meta
+            -> Resource a
+toResource' obj links meta =
   Resource
-    (Identifier (pack . show . myId $ obj) "TestResource")
+    (Identifier (pack . show . uniqueId $ obj) (typeDescriptor obj))
     obj
-    (Just $ objectLinks obj)
-    (Just $ objectMetaData obj)
+    links
+    meta
     Nothing
 
-objectLinks :: TestResource -> Links
-objectLinks obj =
-  toLinks [ ("self", toURL ("/me/" <> (show $ myId obj)))
-          , ("related", toURL ("/friends/" <> (show $ myId obj)))
-          ]
-
-objectMetaData :: TestResource -> Meta Bool
-objectMetaData obj =
-   Meta . Map.fromList $ [ ("isOld", myAge obj > 50) ]
-
 linksObj :: Links
 linksObj = toLinks [ ("self", toURL "/things/1")
                    , ("related", toURL "http://some.domain.com/other/things/1")
@@ -65,11 +89,14 @@
 testObject2 :: TestResource
 testObject2 = TestResource 2 "Carrie Brownstein" 35 "Lunch"
 
-testMetaObj :: Meta TestMetaObject
+otherTestObject :: OtherTestResource
+otherTestObject = OtherTestResource 999 "Atom Smasher" 100 "Atom Smashers, Inc"
+
+testMetaObj :: Meta
 testMetaObj =
-  Meta . Map.fromList $ [ ("importantData", TestMetaObject 3 True) ]
+  Meta . HM.fromList $ [ ("importantData", (AE.toJSON $ TestMetaObject 3 True)) ]
 
-emptyMeta :: Maybe (Meta TestMetaObject)
+emptyMeta :: Maybe Meta
 emptyMeta = Nothing
 
 toURL :: String -> URL
