rest-core-0.39.0.1: src/Rest/Resource.hs
{-# LANGUAGE
CPP
, FlexibleContexts
, FlexibleInstances
, GADTs
, KindSignatures
, MultiParamTypeClasses
, NamedFieldPuns
, NoImplicitPrelude
, RankNTypes
, TypeSynonymInstances
#-}
#if MIN_VERSION_base(4,9,0)
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
#endif
-- | A 'Resource' type for representing a REST resource, as well as
-- smart constructors for empty resources which can then be filled in
-- using record updates.
module Rest.Resource
( Resource (..)
, mkResource
, mkResourceId
, mkResourceReader
, mkResourceReaderWith
, module Rest.Types.Void
) where
import Prelude.Compat
import Control.Monad.Reader
import Rest.Handler
import Rest.Schema (Schema (..), Step (..))
import Rest.Types.Void
-- * The @Resource@ type.
-- | The 'Resource' data type represents a single resource in a REST
-- API. Handlers run in a monad @m@, while things below this resource
-- run in @s@. The identifiers @sid@, @mid@ and @aid@ identify a
-- single item, a listing and an action.
data Resource m s sid mid aid where
Resource :: (Applicative m, Monad m, Applicative s, Monad s) =>
{ name :: String -- ^ The name for this resource, used as a path segment in routing.
, description :: String -- ^ A description of the resource, used for documentation.
, schema :: Schema sid mid aid -- ^ The schema for routing and identification.
, private :: Bool -- ^ Private resources are not documented, but they are exposed.
, enter :: forall b. sid -> s b -> m b -- ^ How to run a subresource given an id.
, list :: mid -> ListHandler m -- ^ List handler, both toplevel and deeper (search).
, statics :: aid -> Handler m -- ^ Static actions, e.g. signin.
, get :: Maybe (Handler s) -- ^ Get a single resource identified by id.
, update :: Maybe (Handler s) -- ^ Update a single resource identified by id.
, remove :: Maybe (Handler s) -- ^ Delete a single resource identified by id.
, create :: Maybe (Handler m) -- ^ Create a single resource, generating a new id.
, actions :: [(String, Handler s)] -- ^ Actions performed on a single resource.
, selects :: [(String, Handler s)] -- ^ Properties of a single resource.
} -> Resource m s sid mid aid
-- * Smart constructors for empty resources.
-- | Create an empty resource given an 'enter' function. It has no
-- name, so if you wish to route to this resource, you should set one.
mkResource :: (Applicative m, Monad m, Applicative s, Monad s) => (forall b. sid -> s b -> m b) -> Resource m s sid Void Void
mkResource e = Resource
{ name = ""
, description = ""
, schema = Schema Nothing (Named [])
, private = False
, enter = e
, list = magic
, statics = magic
, get = Nothing
, update = Nothing
, remove = Nothing
, create = Nothing
, actions = []
, selects = []
}
-- | Make a resource that doesn't add any information for
-- subresources (i.e. 'enter' is set to 'id').
mkResourceId :: (Applicative m, Monad m) => Resource m m sid Void Void
mkResourceId = mkResource (const id)
-- | Make a resource that provides the single resource identifier to
-- its subresources.
mkResourceReader :: (Applicative m, Monad m) => Resource m (ReaderT sid m) sid Void Void
mkResourceReader = mkResourceReaderWith id
-- | Make a resource that provides the single resource identifier to
-- its subresources, by giving a conversion function to a 'ReaderT'.
-- If @s@ is a newtype around 'ReaderT', for example, the function
-- should unwrap the newtype.
mkResourceReaderWith :: (Applicative m, Monad m, Applicative s, Monad s) => (forall b. s b -> ReaderT sid m b) -> Resource m s sid Void Void
mkResourceReaderWith f = mkResource (\a -> flip runReaderT a . f)