------------------------------------------------------------------------------ module Snap.Snaplet.Rest.Config ( -- * Configuration ResourceConfig (..) , defaultConfig -- * Snaplet type class , HasResourceConfig (..) , Resources , resourceInit , resourceInitDefault -- * Local utility , getResourceConfig ) where ------------------------------------------------------------------------------ import qualified Data.ByteString as BS ------------------------------------------------------------------------------ import Control.Monad.State (get) import Data.Int (Int64) import Data.Text (Text) import Snap.Core import Snap.Snaplet ------------------------------------------------------------------------------ -- | Configuration data. data ResourceConfig m = ResourceConfig { -- | The maximum number of members to retrieve from a collection in -- a single request. readLimit :: Maybe Int -- | Maximum size of request bodies allowed when receiving resources. , maxRequestBodySize :: Int64 -- | Action to run if the request header parsing fails. , onHeaderFailure :: m () -- | Action to run if the resource path parsing fails. , onPathFailure :: m () -- | Action to run if the URL query string parsing fails. , onQueryFailure :: m () -- | Action to run if the requested resource cannot be found. , onLookupFailure :: m () -- | Action to run an invalid method is requested on a resource. , onMethodFailure :: m () -- | Action to run if the response media type is not supported. , onAcceptFailure :: m () -- | Action to run if the request media type is not supported. , onContentTypeFailure :: m () -- | Action to run if the request body parse fails. , onContentParseFailure :: m () } ------------------------------------------------------------------------------ -- | The default configuration settings. Requires a value for the maximum -- size of a request body. -- -- > defaultConfig mrbs = ResourceConfig -- > { readLimit = Nothing -- > , maxRequestBodySize = mrbs -- > , on*Failure = write "reason" -- > } defaultConfig :: MonadSnap m => Int64 -> ResourceConfig m defaultConfig mrbs = ResourceConfig { readLimit = Nothing , maxRequestBodySize = mrbs , onHeaderFailure = write "Failed to parse request headers\n" , onPathFailure = write "Failed to parse resource path\n" , onQueryFailure = write "Failed to parse query string\n" , onLookupFailure = write "Failed to find resource\n" , onMethodFailure = write "Method not allowed\n" , onAcceptFailure = write "No required media types are supported\n" , onContentTypeFailure = write "No parser for request content available\n" , onContentParseFailure = write "Failed to parse request content\n" } where write msg = do modifyResponse $ setContentType "text/plain" . setContentLength (fromIntegral $ BS.length msg) writeBS msg ------------------------------------------------------------------------------ -- | The type class for an implementing Snaplet. class HasResourceConfig b where -- | Retrieve the configuration from the Snaplet monad. resourceLens :: SnapletLens (Snaplet b) (ResourceConfig (Handler b b)) ------------------------------------------------------------------------------ -- | Convenience alias of 'ResourceConfig'. type Resources b = ResourceConfig (Handler b b) ------------------------------------------------------------------------------ -- | Initialize the resource snaplet with the given configuration. resourceInit :: ResourceConfig (Handler b b) -> SnapletInit b (Resources b) resourceInit = makeSnaplet snapletName snapletDescription Nothing . return ------------------------------------------------------------------------------ -- | Initialize the resource snaplet with the default configuration. resourceInitDefault :: Int64 -> SnapletInit b (Resources b) resourceInitDefault mrbs = makeSnaplet snapletName snapletDescription Nothing $ return $ defaultConfig mrbs ------------------------------------------------------------------------------ snapletName :: Text snapletName = "rest-resources" ------------------------------------------------------------------------------ snapletDescription :: Text snapletDescription = "REST resources" ------------------------------------------------------------------------------ -- | Returns the resource configuration. getResourceConfig :: HasResourceConfig b => Handler b v (ResourceConfig (Handler b b)) getResourceConfig = withTop' resourceLens get