module Network.JSONApi.Document
( Document
, ResourceData (..)
, ErrorDocument (..)
, Included
, mkDocument
, mkDocument'
, singleton
, list
, mkCompoundDocument
, mkCompoundDocument'
, mkIncludedResource
) where
import Control.Monad (mzero)
import Data.Aeson
( ToJSON
, FromJSON
, Value
, (.=)
, (.:)
, (.:?)
)
import qualified Data.Aeson as AE
import Data.Monoid
import qualified GHC.Generics as G
import qualified Network.JSONApi.Error as E
import Network.JSONApi.Link as L
import Network.JSONApi.Meta as M
import Network.JSONApi.Resource (Resource, ResourcefulEntity)
import qualified Network.JSONApi.Resource as R
data Document a = Document
{ _data :: ResourceData a
, _links :: Maybe Links
, _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)
data Included = Included [Value]
deriving (Show)
instance Monoid Included where
mempty = Included []
mappend (Included as) (Included bs) = Included (as <> bs)
mkDocument :: ResourcefulEntity a =>
[a]
-> Maybe Links
-> Maybe Meta
-> Document a
mkDocument res = mkDocument' (toResourceData res)
mkDocument' :: ResourceData a
-> Maybe Links
-> Maybe Meta
-> Document a
mkDocument' res links meta =
Document
{ _data = res
, _links = links
, _meta = meta
, _included = []
}
mkCompoundDocument :: ResourcefulEntity a =>
[a]
-> Maybe Links
-> Maybe Meta
-> Included
-> Document a
mkCompoundDocument res = mkCompoundDocument' (toResourceData res)
mkCompoundDocument' :: ResourceData a
-> Maybe Links
-> Maybe Meta
-> Included
-> Document a
mkCompoundDocument' res links meta (Included included) =
Document
{ _data = res
, _links = links
, _meta = meta
, _included = included
}
mkIncludedResource :: ResourcefulEntity a => a -> Included
mkIncludedResource res = Included [AE.toJSON . R.toResource $ res]
toResourceData :: ResourcefulEntity a => [a] -> ResourceData a
toResourceData (r:[]) = Singleton (R.toResource r)
toResourceData rs = List (map R.toResource rs)
data ResourceData a = Singleton (Resource a)
| List [ Resource a ]
deriving (Show, Eq, G.Generic)
singleton :: ResourcefulEntity a => a -> ResourceData a
singleton = Singleton . R.toResource
list :: ResourcefulEntity a => [a] -> ResourceData a
list = List . map R.toResource
instance (ToJSON a) => ToJSON (ResourceData a) where
toJSON (Singleton res) = AE.toJSON res
toJSON (List res) = AE.toJSON res
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
data ErrorDocument a = ErrorDocument
{ _error :: E.Error a
, _errorLinks :: Maybe Links
, _errorMeta :: Maybe Meta
} deriving (Show, Eq, G.Generic)
instance (ToJSON a) => ToJSON (ErrorDocument a) where
toJSON (ErrorDocument err links meta) =
AE.object [ "error" .= err
, "links" .= links
, "meta" .= meta
]
instance (FromJSON a) => FromJSON (ErrorDocument a) where
parseJSON = AE.withObject "error" $ \v ->
ErrorDocument
<$> v .: "error"
<*> v .:? "links"
<*> v .:? "meta"