{-# LANGUAGE FlexibleInstances, IncoherentInstances #-} ------------------------------------------------------------------------------ module Snap.Snaplet.Rest.Resource.Internal ( Resource (..) , resource , complete , PutAction (..) ) where ------------------------------------------------------------------------------ import Control.Applicative import Data.ByteString (ByteString) import Data.Maybe import Network.HTTP.Media (MediaType) import Snap.Core (Params) ------------------------------------------------------------------------------ import Snap.Snaplet.Rest.FromRequest.Internal (FromRequest (..)) import Snap.Snaplet.Rest.Proxy (Proxy (..)) ------------------------------------------------------------------------------ -- | A resource descriptor for the type 'res'. The resource runs in the monad -- 'm', identifies resources with values of the type 'id', and describes -- changes with value of the type 'diff'. data Resource res m id diff = Resource { renderers :: [(MediaType, res -> m ByteString)] , parsers :: [(MediaType, ByteString -> m (Maybe res))] , diffParsers :: [(MediaType, ByteString -> m (Maybe diff))] , listRenderers :: [(MediaType, [res] -> m ByteString)] , listParsers :: [(MediaType, ByteString -> m (Maybe [res]))] , create :: Maybe (res -> m ()) , retrieve :: Maybe (id -> m [res]) , update :: Maybe (id -> diff -> m Bool) , toDiff :: Maybe (res -> diff) , delete :: Maybe (id -> m Bool) , fromParams :: Maybe (Params -> Maybe id) , putAction :: Maybe PutAction , patchEnabled :: Bool } ------------------------------------------------------------------------------ class Diff a b where defaultToDiff :: Maybe (a -> b) isDifferentType :: Proxy (a, b) -> Bool instance Diff a a where defaultToDiff = Just id isDifferentType _ = False instance Diff a b where defaultToDiff = Nothing isDifferentType _ = True ------------------------------------------------------------------------------ -- | The empty resource descriptor, useful as a starting point for building -- resources. resource :: Resource res m id diff resource = Resource [] [] [] [] [] Nothing Nothing Nothing Nothing Nothing Nothing Nothing False ------------------------------------------------------------------------------ complete :: FromRequest id => Resource res m id diff -> Resource res m id diff complete = complete' Proxy complete' :: FromRequest id => Proxy (res, diff) -> Resource res m id diff -> Resource res m id diff complete' p r = r { toDiff = toDiff r <|> defaultToDiff , fromParams = fromParams r <|> defaultFromParams , putAction = putAction r <|> defaultPutAction , patchEnabled = isDifferentType p } where hasCreate = isJust $ create r hasUpdate = isJust $ update r defaultPutAction | hasCreate && not hasUpdate = Just Create | hasUpdate && not hasCreate = Just Update | otherwise = Nothing ------------------------------------------------------------------------------ -- | Indicates which action that a PUT request should take for a resource. data PutAction = Create -- ^ Always create | Update -- ^ Always update deriving (Eq, Show)