-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Another Haskell web toolkit based on scotty -- @package Spock @version 0.4.3.2 module Web.Spock -- | Run a spock application using the warp server, a given db storageLayer -- and an initial state. Spock works with database libraries that already -- implement connection pooling and with those that don't come with it -- out of the box. For more see the PoolOrConn type. spock :: Int -> SessionCfg sess -> PoolOrConn conn -> st -> SpockM conn sess st () -> IO () -- | Spock is supercharged Scotty, that's why the SpockM is built on -- the ScottyT monad. Insive the SpockM monad, you may define routes and -- middleware. type SpockM conn sess st a = ScottyT Text (WebStateM conn sess st) a -- | The SpockAction is the monad of all route-actions. You have access to -- the database, session and state of your application. type SpockAction conn sess st a = ActionT Text (WebStateM conn sess st) a -- | You can feed Spock with either a connection pool, or instructions on -- how to build a connection pool. See ConnBuilder data PoolOrConn a PCPool :: (Pool a) -> PoolOrConn a PCConduitPool :: (Pool a) -> PoolOrConn a PCConn :: (ConnBuilder a) -> PoolOrConn a -- | The ConnBuilder instructs Spock how to create or close a database -- connection. data ConnBuilder a ConnBuilder :: IO a -> (a -> IO ()) -> PoolCfg -> ConnBuilder a cb_createConn :: ConnBuilder a -> IO a cb_destroyConn :: ConnBuilder a -> a -> IO () cb_poolConfiguration :: ConnBuilder a -> PoolCfg -- | If Spock should take care of connection pooling, you need to configure -- it depending on what you need. data PoolCfg PoolCfg :: Int -> Int -> NominalDiffTime -> PoolCfg pc_stripes :: PoolCfg -> Int pc_resPerStripe :: PoolCfg -> Int pc_keepOpenTime :: PoolCfg -> NominalDiffTime class HasSpock m runQuery :: HasSpock m => (SpockConn m -> IO a) -> m a getState :: HasSpock m => m (SpockState m) -- | Configuration for the session manager data SessionCfg a SessionCfg :: Text -> NominalDiffTime -> Int -> a -> SessionCfg a sc_cookieName :: SessionCfg a -> Text sc_sessionTTL :: SessionCfg a -> NominalDiffTime sc_sessionIdEntropy :: SessionCfg a -> Int sc_emptySession :: SessionCfg a -> a -- | Read the stored session readSession :: SpockAction conn sess st sess -- | Write to the current session. Note that all data is stored on the -- server. The user only reciedes a sessionId to be identified. writeSession :: sess -> SpockAction conn sess st () -- | Modify the stored session modifySession :: (sess -> sess) -> SpockAction conn sess st () -- | Set a cookie living for a given number of seconds setCookie :: (SpockError e, MonadIO m) => Text -> Text -> NominalDiffTime -> ActionT e m () -- | Set a cookie living until a specific UTCTime setCookie' :: (SpockError e, MonadIO m) => Text -> Text -> UTCTime -> ActionT e m () -- | Read a cookie previously set in the users browser for your site getCookie :: (SpockError e, MonadIO m) => Text -> ActionT e m (Maybe Text) -- | SafeActions are actions that need to be protected from csrf attacks class (Hashable a, Eq a, Typeable a) => SafeAction a runSafeAction :: SafeAction a => a -> SpockAction conn sess st () -- | Wire up a safe action: Safe actions are actions that are protected -- from csrf attacks. Here's a usage example: -- --
-- newtype DeleteUser = DeleteUser Int deriving (Hashable, Typeable, Eq) -- -- instance SafeAction DeleteUser where -- runSafeAction (DeleteUser i) = -- do runQuery $ deleteUserFromDb i -- redirect "/user-list" -- -- get "/user-details/:userId" $ -- do userId <- param "userId" -- deleteUrl <- safeActionPath (DeleteUser userId) -- html $ TL.concat [ "Click <a href='", TL.fromStrict deleteUrl, "'>here</a> to delete user!" ] ---- -- Note that safeActions currently only support GET and POST requests. safeActionPath :: SafeAction a => a -> SpockAction conn sess st Text -- | get = addroute GET get :: (ScottyError e, MonadIO m) => RoutePattern -> ActionT e m () -> ScottyT e m () -- | post = addroute POST post :: (ScottyError e, MonadIO m) => RoutePattern -> ActionT e m () -> ScottyT e m () -- | put = addroute PUT put :: (ScottyError e, MonadIO m) => RoutePattern -> ActionT e m () -> ScottyT e m () -- | delete = addroute DELETE delete :: (ScottyError e, MonadIO m) => RoutePattern -> ActionT e m () -> ScottyT e m () -- | patch = addroute PATCH patch :: (ScottyError e, MonadIO m) => RoutePattern -> ActionT e m () -> ScottyT e m () -- | Define a route with a StdMethod, Text value representing -- the path spec, and a body (Action) which modifies the -- response. -- --
-- addroute GET "/" $ text "beam me up!" ---- -- The path spec can include values starting with a colon, which are -- interpreted as captures. These are named wildcards that can be -- looked up with param. -- --
-- addroute GET "/foo/:bar" $ do -- v <- param "bar" -- text v ---- --
-- >>> curl http://localhost:3000/foo/something -- something --addroute :: (ScottyError e, MonadIO m) => StdMethod -> RoutePattern -> ActionT e m () -> ScottyT e m () -- | HTTP standard method (as defined by RFC 2616, and PATCH which is -- defined by RFC 5789). data StdMethod :: * GET :: StdMethod POST :: StdMethod HEAD :: StdMethod PUT :: StdMethod DELETE :: StdMethod TRACE :: StdMethod CONNECT :: StdMethod OPTIONS :: StdMethod PATCH :: StdMethod -- | Use given middleware. Middleware is nested such that the first -- declared is the outermost middleware (it has first dibs on the request -- and last action on the response). Every middleware is run on each -- request. middleware :: Monad m => Middleware -> ScottyT e m () -- | Add a route that matches regardless of the HTTP verb. matchAny :: (ScottyError e, MonadIO m) => RoutePattern -> ActionT e m () -> ScottyT e m () -- | Specify an action to take if nothing else is found. Note: this -- _always_ matches, so should generally be the last route specified. notFound :: (ScottyError e, MonadIO m) => ActionT e m () -> ScottyT e m () -- | Get the Request object. request :: (ScottyError e, Monad m) => ActionT e m Request -- | Get a request header. Header name is case-insensitive. (Deprecated in -- favor of header.) reqHeader :: (ScottyError e, Monad m) => Text -> ActionT e m (Maybe Text) -- | Get the request body. body :: (ScottyError e, Monad m) => ActionT e m ByteString -- | Get a parameter. First looks in captures, then form data, then query -- parameters. -- --
-- redirect "http://www.google.com" ---- -- OR -- --
-- redirect "/foo/bar" --redirect :: (ScottyError e, Monad m) => Text -> ActionT e m a -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/plain". text :: (ScottyError e, Monad m) => Text -> ActionT e m () -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/html". html :: (ScottyError e, Monad m) => Text -> ActionT e m () -- | Send a file as the response. Doesn't set the "Content-Type" header, so -- you probably want to do that on your own with setHeader. file :: (ScottyError e, Monad m) => FilePath -> ActionT e m () -- | Set the body of the response to the JSON encoding of the given value. -- Also sets "Content-Type" header to "application/json". json :: (ToJSON a, ScottyError e, Monad m) => a -> ActionT e m () -- | Set the body of the response to a Source. Doesn't set the -- "Content-Type" header, so you probably want to do that on your own -- with setHeader. source :: (ScottyError e, Monad m) => Source IO (Flush Builder) -> ActionT e m () -- | Set the body of the response to the given ByteString value. -- Doesn't set the "Content-Type" header, so you probably want to do that -- on your own with setHeader. raw :: (ScottyError e, Monad m) => ByteString -> ActionT e m () -- | Throw an exception, which can be caught with rescue. Uncaught -- exceptions turn into HTTP 500 responses. raise :: (ScottyError e, Monad m) => e -> ActionT e m a -- | Catch an exception thrown by raise. -- --
-- raise "just kidding" `rescue` (\msg -> text msg) --rescue :: (ScottyError e, Monad m) => ActionT e m a -> (e -> ActionT e m a) -> ActionT e m a -- | Abort execution of this action and continue pattern matching routes. -- Like an exception, any code after next is not executed. -- -- As an example, these two routes overlap. The only way the second one -- will ever run is if the first one calls next. -- --
-- get "/foo/:bar" $ do -- w :: Text <- param "bar" -- unless (w == "special") next -- text "You made a request to /foo/special" -- -- get "/foo/:baz" $ do -- w <- param "baz" -- text $ "You made a request to: " <> w --next :: (ScottyError e, Monad m) => ActionT e m a data RoutePattern :: * -- | Same as "param", but the target type needs to implement -- PathPiece paramPathPiece :: PathPiece s => Text -> SpockAction conn sess st s -- | Read the heart of Spock. This is useful if you want to construct your -- own monads that work with runQuery and getState using "runSpockIO" getSpockHeart :: MonadTrans t => t (WebStateM conn sess st) (WebState conn sess st) -- | Run an action inside of Spocks core monad. This allows you to use -- runQuery and getState runSpockIO :: WebState conn sess st -> WebStateM conn sess st a -> IO a data WebStateM conn sess st a data WebState conn sess st