-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Haskell web framework inspired by Ruby's Sinatra, using WAI and Warp -- -- A Haskell web framework inspired by Ruby's Sinatra, using WAI and -- Warp. -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   
--   import Web.Scotty
--   
--   main = scotty 3000 $
--     get "/:word" $ do
--       beam <- pathParam "word"
--       html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]
--   
-- -- Scotty is the cheap and cheerful way to write RESTful, declarative web -- applications. -- -- -- -- As for the name: Sinatra + Warp = Scotty. -- -- @package scotty @version 0.21 module Web.Scotty.Internal.Types data Options Options :: Int -> Settings -> Options -- | 0 = silent, 1(def) = startup banner [verbose] :: Options -> Int -- | Warp Settings Note: to work around an issue in warp, the -- default FD cache duration is set to 0 so changes to static files are -- always picked up. This likely has performance implications, so you may -- want to modify this for production servers using -- setFdCacheDuration. [settings] :: Options -> Settings defaultOptions :: Options newtype RouteOptions RouteOptions :: Maybe Kilobytes -> RouteOptions [maxRequestBodySize] :: RouteOptions -> Maybe Kilobytes defaultRouteOptions :: RouteOptions type Kilobytes = Int type Middleware m = Application m -> Application m type Application m = Request -> m Response data BodyChunkBuffer BodyChunkBuffer :: Bool -> [ByteString] -> BodyChunkBuffer -- | whether we've reached the end of the stream yet [hasFinishedReadingChunks] :: BodyChunkBuffer -> Bool [chunksReadSoFar] :: BodyChunkBuffer -> [ByteString] -- | The key part of having two MVars is that we can "clone" the BodyInfo -- to create a copy where the index is reset to 0, but the chunk cache is -- the same. Passing a cloned BodyInfo into each matched route allows -- them each to start from the first chunk if they call bodyReader. -- -- Introduced in (#308) data BodyInfo BodyInfo :: MVar Int -> MVar BodyChunkBuffer -> IO ByteString -> BodyInfo -- | index into the stream read so far [bodyInfoReadProgress] :: BodyInfo -> MVar Int [bodyInfoChunkBuffer] :: BodyInfo -> MVar BodyChunkBuffer -- | can be called to get more chunks [bodyInfoDirectChunkRead] :: BodyInfo -> IO ByteString data ScottyState m ScottyState :: [Middleware] -> [BodyInfo -> Middleware m] -> Maybe (ErrorHandler m) -> RouteOptions -> ScottyState m [middlewares] :: ScottyState m -> [Middleware] [routes] :: ScottyState m -> [BodyInfo -> Middleware m] [handler] :: ScottyState m -> Maybe (ErrorHandler m) [routeOptions] :: ScottyState m -> RouteOptions defaultScottyState :: ScottyState m addMiddleware :: Middleware -> ScottyState m -> ScottyState m addRoute :: (BodyInfo -> Middleware m) -> ScottyState m -> ScottyState m setHandler :: Maybe (ErrorHandler m) -> ScottyState m -> ScottyState m updateMaxRequestBodySize :: RouteOptions -> ScottyState m -> ScottyState m newtype ScottyT m a ScottyT :: State (ScottyState m) a -> ScottyT m a [runS] :: ScottyT m a -> State (ScottyState m) a -- | Internal exception mechanism used to modify the request processing -- flow. -- -- The exception constructor is not exposed to the user and all -- exceptions of this type are caught and processed within the -- runAction function. data ActionError -- | Redirect AERedirect :: Text -> ActionError -- | Stop processing this route and skip to the next one AENext :: ActionError -- | Stop processing the request AEFinish :: ActionError tryNext :: MonadUnliftIO m => m a -> m Bool -- | E.g. when a parameter is not found in a query string (400 Bad Request) -- or when parsing a JSON body fails (422 Unprocessable Entity) -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined data StatusError -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined StatusError :: Status -> Text -> StatusError -- | Specializes a Handler to the ActionT monad type ErrorHandler m = Handler (ActionT m) () -- | Thrown e.g. when a request is too large data ScottyException RequestTooLarge :: ScottyException MalformedJSON :: ByteString -> Text -> ScottyException FailedToParseJSON :: ByteString -> Text -> ScottyException PathParameterNotFound :: Text -> ScottyException QueryParameterNotFound :: Text -> ScottyException FormFieldNotFound :: Text -> ScottyException FailedToParseParameter :: Text -> Text -> Text -> ScottyException type Param = (Text, Text) type File = (Text, FileInfo ByteString) data ActionEnv Env :: Request -> [Param] -> [Param] -> [Param] -> IO ByteString -> IO ByteString -> [File] -> TVar ScottyResponse -> ActionEnv [envReq] :: ActionEnv -> Request [envPathParams] :: ActionEnv -> [Param] [envFormParams] :: ActionEnv -> [Param] [envQueryParams] :: ActionEnv -> [Param] [envBody] :: ActionEnv -> IO ByteString [envBodyChunk] :: ActionEnv -> IO ByteString [envFiles] :: ActionEnv -> [File] [envResponse] :: ActionEnv -> TVar ScottyResponse getResponse :: MonadIO m => ActionEnv -> m ScottyResponse getResponseAction :: MonadIO m => ActionT m ScottyResponse modifyResponse :: MonadIO m => (ScottyResponse -> ScottyResponse) -> ActionT m () data BodyPartiallyStreamed BodyPartiallyStreamed :: BodyPartiallyStreamed data Content ContentBuilder :: Builder -> Content ContentFile :: FilePath -> Content ContentStream :: StreamingBody -> Content ContentResponse :: Response -> Content data ScottyResponse SR :: Status -> ResponseHeaders -> Content -> ScottyResponse [srStatus] :: ScottyResponse -> Status [srHeaders] :: ScottyResponse -> ResponseHeaders [srContent] :: ScottyResponse -> Content setContent :: Content -> ScottyResponse -> ScottyResponse setHeaderWith :: ([(HeaderName, ByteString)] -> [(HeaderName, ByteString)]) -> ScottyResponse -> ScottyResponse setStatus :: Status -> ScottyResponse -> ScottyResponse -- | The default response has code 200 OK and empty body defaultScottyResponse :: ScottyResponse newtype ActionT m a ActionT :: ReaderT ActionEnv m a -> ActionT m a [runAM] :: ActionT m a -> ReaderT ActionEnv m a -- | catches either ActionError (thrown by next), -- ScottyException (thrown if e.g. a query parameter is not found) -- or StatusError (via raiseStatus) tryAnyStatus :: MonadUnliftIO m => m a -> m Bool data RoutePattern Capture :: Text -> RoutePattern Literal :: Text -> RoutePattern Function :: (Request -> Maybe [Param]) -> RoutePattern instance GHC.Show.Show Web.Scotty.Internal.Types.ActionError instance GHC.Show.Show Web.Scotty.Internal.Types.StatusError instance GHC.Show.Show Web.Scotty.Internal.Types.ScottyException instance GHC.Show.Show Web.Scotty.Internal.Types.BodyPartiallyStreamed instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.Trans.Control.MonadTransControl Web.Scotty.Internal.Types.ActionT instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.Trans.Class.MonadTrans Web.Scotty.Internal.Types.ActionT instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Web.Scotty.Internal.Types.ActionT m) instance GHC.Base.Monad m => GHC.Base.Monad (Web.Scotty.Internal.Types.ActionT m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Web.Scotty.Internal.Types.ActionT m) instance GHC.Base.Functor m => GHC.Base.Functor (Web.Scotty.Internal.Types.ActionT m) instance GHC.Base.Monad (Web.Scotty.Internal.Types.ScottyT m) instance GHC.Base.Applicative (Web.Scotty.Internal.Types.ScottyT m) instance GHC.Base.Functor (Web.Scotty.Internal.Types.ScottyT m) instance Data.String.IsString Web.Scotty.Internal.Types.RoutePattern instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Web.Scotty.Internal.Types.ScottyT m a) instance GHC.Base.Monoid a => GHC.Base.Monoid (Web.Scotty.Internal.Types.ScottyT m a) instance Data.Default.Class.Default (Web.Scotty.Internal.Types.ScottyState m) instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.Error.Class.MonadError Web.Scotty.Internal.Types.StatusError (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.Fail.MonadFail (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.IO.Unlift.MonadUnliftIO m => GHC.Base.Alternative (Web.Scotty.Internal.Types.ActionT m) instance Control.Monad.IO.Unlift.MonadUnliftIO m => GHC.Base.MonadPlus (Web.Scotty.Internal.Types.ActionT m) instance (GHC.Base.Monad m, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Web.Scotty.Internal.Types.ActionT m a) instance (GHC.Base.Monad m, GHC.Base.Monoid a) => GHC.Base.Monoid (Web.Scotty.Internal.Types.ActionT m a) instance Data.Default.Class.Default Web.Scotty.Internal.Types.ScottyResponse instance GHC.Exception.Type.Exception Web.Scotty.Internal.Types.BodyPartiallyStreamed instance GHC.Exception.Type.Exception Web.Scotty.Internal.Types.ScottyException instance GHC.Exception.Type.Exception Web.Scotty.Internal.Types.StatusError instance GHC.Exception.Type.Exception Web.Scotty.Internal.Types.ActionError instance Data.Default.Class.Default Web.Scotty.Internal.Types.RouteOptions instance Data.Default.Class.Default Web.Scotty.Internal.Types.Options -- | This module provides utilities for adding cookie support inside -- scotty applications. Most code has been adapted from -- 'scotty-cookie'. -- --

Example

-- -- A simple hit counter that stores the number of page visits in a -- cookie: -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   
--   import Control.Monad
--   import Data.Monoid
--   import Data.Maybe
--   import qualified Data.Text.Lazy as TL
--   import qualified Data.Text.Lazy.Read as TL (decimal)
--   import Web.Scotty (scotty, html)
--   import Web.Scotty.Cookie (getCookie, setSimpleCookie)
--   
--   main :: IO ()
--   main = scotty 3000 $
--       get "/" $ do
--           hits <- liftM (fromMaybe "0") $ getCookie "hits"
--           let hits' =
--                 case TL.decimal hits of
--                   Right n -> TL.pack . show . (+1) $ (fst n :: Integer)
--                   Left _  -> "1"
--           setSimpleCookie "hits" $ TL.toStrict hits'
--           html $ mconcat [ "<html><body>"
--                          , hits'
--                          , "</body></html>"
--                          ]
--   
module Web.Scotty.Cookie -- | Set a cookie, with full access to its options (see SetCookie) setCookie :: MonadIO m => SetCookie -> ActionT m () -- | makeSimpleCookie and setCookie combined. setSimpleCookie :: MonadIO m => Text -> Text -> ActionT m () -- | Lookup one cookie name getCookie :: Monad m => Text -> ActionT m (Maybe Text) -- | Returns all cookies getCookies :: Monad m => ActionT m CookiesText -- | Browsers don't directly delete a cookie, but setting its expiry to a -- past date (e.g. the UNIX epoch) ensures that the cookie will be -- invalidated (whether and when it will be actually deleted by the -- browser seems to be browser-dependent). deleteCookie :: MonadIO m => Text -> ActionT m () -- | Textual cookies. Functions assume UTF8 encoding. type CookiesText = [(Text, Text)] -- | Construct a simple cookie (an UTF-8 string pair with default cookie -- options) makeSimpleCookie :: Text -> Text -> SetCookie -- | Data type representing the key-value pair to use for a cookie, as well -- as configuration options for it. -- --

Creating a SetCookie

-- -- SetCookie does not export a constructor; instead, use -- defaultSetCookie and override values (see -- http://www.yesodweb.com/book/settings-types for details): -- --
--   import Web.Cookie
--   :set -XOverloadedStrings
--   let cookie = defaultSetCookie { setCookieName = "cookieName", setCookieValue = "cookieValue" }
--   
-- --

Cookie Configuration

-- -- Cookies have several configuration options; a brief summary of each -- option is given below. For more information, see RFC 6265 or -- Wikipedia. data SetCookie -- | A minimal SetCookie. All fields are Nothing or -- False except setCookieName = "name" and -- setCookieValue = "value". You need this to construct a -- SetCookie, because it does not export a constructor. -- Equivalently, you may use def. defaultSetCookie :: SetCookie -- | The name of the cookie. Default value: "name" setCookieName :: SetCookie -> ByteString -- | The value of the cookie. Default value: "value" setCookieValue :: SetCookie -> ByteString -- | The URL path for which the cookie should be sent. Default value: -- Nothing (The browser defaults to the path of the request that -- sets the cookie). setCookiePath :: SetCookie -> Maybe ByteString -- | The time at which to expire the cookie. Default value: -- Nothing (The browser will default to expiring a cookie when -- the browser is closed). setCookieExpires :: SetCookie -> Maybe UTCTime -- | The maximum time to keep the cookie, in seconds. Default value: -- Nothing (The browser defaults to expiring a cookie when the -- browser is closed). setCookieMaxAge :: SetCookie -> Maybe DiffTime -- | The domain for which the cookie should be sent. Default value: -- Nothing (The browser defaults to the current domain). setCookieDomain :: SetCookie -> Maybe ByteString -- | Marks the cookie as "HTTP only", i.e. not accessible from Javascript. -- Default value: False setCookieHttpOnly :: SetCookie -> Bool -- | Instructs the browser to only send the cookie over HTTPS. Default -- value: False setCookieSecure :: SetCookie -> Bool -- | The "same site" policy of the cookie, i.e. whether it should be sent -- with cross-site requests. Default value: Nothing setCookieSameSite :: SetCookie -> Maybe SameSiteOption -- | Data type representing the options for a SameSite cookie data SameSiteOption -- | Directs the browser to send the cookie for cross-site requests. sameSiteNone :: SameSiteOption -- | Directs the browser to send the cookie for safe requests (e.g. -- GET), but not for unsafe ones (e.g. POST) sameSiteLax :: SameSiteOption -- | Directs the browser to not send the cookie for any cross-site -- request, including e.g. a user clicking a link in their email to open -- a page on your site. sameSiteStrict :: SameSiteOption -- | It should be noted that most of the code snippets below depend on the -- OverloadedStrings language pragma. -- -- The functions in this module allow an arbitrary monad to be embedded -- in Scotty's monad transformer stack, e.g. for complex endpoint -- configuration, interacting with databases etc. -- -- Scotty is set up by default for development mode. For production -- servers, you will likely want to modify settings and the -- defaultHandler. See the comments on each of these functions for -- more information. -- -- Please refer to the examples directory and the spec -- test suite for concrete use cases, e.g. constructing responses, -- exception handling and useful implementation details. module Web.Scotty.Trans -- | Run a scotty application using the warp server. NB: scotty p === -- scottyT p id scottyT :: (Monad m, MonadIO n) => Port -> (m Response -> IO Response) -> ScottyT m () -> n () -- | Run a scotty application using the warp server, passing extra options. -- NB: scottyOpts opts === scottyOptsT opts id scottyOptsT :: (Monad m, MonadIO n) => Options -> (m Response -> IO Response) -> ScottyT m () -> n () -- | Run a scotty application using the warp server, passing extra options, -- and listening on the provided socket. NB: scottySocket opts sock === -- scottySocketT opts sock id scottySocketT :: (Monad m, MonadIO n) => Options -> Socket -> (m Response -> IO Response) -> ScottyT m () -> n () data Options Options :: Int -> Settings -> Options -- | 0 = silent, 1(def) = startup banner [verbose] :: Options -> Int -- | Warp Settings Note: to work around an issue in warp, the -- default FD cache duration is set to 0 so changes to static files are -- always picked up. This likely has performance implications, so you may -- want to modify this for production servers using -- setFdCacheDuration. [settings] :: Options -> Settings defaultOptions :: Options -- | Turn a scotty application into a WAI Application, which can be -- run with any WAI handler. NB: scottyApp === scottyAppT id scottyAppT :: (Monad m, Monad n) => (m Response -> IO Response) -> ScottyT m () -> n Application -- | 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 :: Middleware -> ScottyT m () -- | get = addroute GET get :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | post = addroute POST post :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | put = addroute PUT put :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | delete = addroute DELETE delete :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | patch = addroute PATCH patch :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | options = addroute OPTIONS options :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | Define a route with a StdMethod, a route pattern representing -- the path spec, and an Action which may modify the response. -- --
--   get "/" $ text "beam me up!"
--   
-- -- The path spec can include values starting with a colon, which are -- interpreted as captures. These are parameters that can be -- looked up with pathParam. -- --
--   >>> :{
--   let server = S.get "/foo/:bar" (S.pathParam "bar" >>= S.text)
--    in do
--         withScotty server $ curl "http://localhost:3000/foo/something"
--   :}
--   "something"
--   
addroute :: MonadUnliftIO m => StdMethod -> RoutePattern -> ActionT m () -> ScottyT m () -- | Add a route that matches regardless of the HTTP verb. matchAny :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | Specify an action to take if nothing else is found. Note: this -- _always_ matches, so should generally be the last route specified. notFound :: MonadUnliftIO m => ActionT m () -> ScottyT m () -- | Set global size limit for the request body. Requests with body size -- exceeding the limit will not be processed and an HTTP response 413 -- will be returned to the client. Size limit needs to be greater than 0, -- otherwise the application will terminate on start. setMaxRequestBodySize :: Kilobytes -> ScottyT m () -- | Standard Sinatra-style route. Named captures are prepended with -- colons. This is the default route type generated by OverloadedString -- routes. i.e. -- --
--   get (capture "/foo/:bar") $ ...
--   
-- -- and -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   ...
--   get "/foo/:bar" $ ...
--   
-- -- are equivalent. capture :: String -> RoutePattern -- | Match requests using a regular expression. Named captures are not yet -- supported. -- --
--   >>> :{
--   let server = S.get (S.regex "^/f(.*)r$") $ do
--                   cap <- S.pathParam "1"
--                   S.text cap
--    in do
--         withScotty server $ curl "http://localhost:3000/foo/bar"
--   :}
--   "oo/ba"
--   
regex :: String -> RoutePattern -- | Build a route based on a function which can match using the entire -- Request object. Nothing indicates the route does not -- match. A Just value indicates a successful match, optionally -- returning a list of key-value pairs accessible by param. -- --
--   >>> :{
--   let server = S.get (function $ \req -> Just [("version", T.pack $ show $ W.httpVersion req)]) $ do
--                   v <- S.pathParam "version"
--                   S.text v
--    in do
--         withScotty server $ curl "http://localhost:3000/"
--   :}
--   "HTTP/1.1"
--   
function :: (Request -> Maybe [Param]) -> RoutePattern -- | Build a route that requires the requested path match exactly, without -- captures. literal :: String -> RoutePattern -- | Get the Request object. request :: Monad m => ActionT m Request -- | Get a request header. Header name is case-insensitive. header :: Monad m => Text -> ActionT m (Maybe Text) -- | Get all the request headers. Header names are case-insensitive. headers :: Monad m => ActionT m [(Text, Text)] -- | Get the request body. body :: MonadIO m => ActionT m ByteString -- | Get an IO action that reads body chunks -- -- bodyReader :: Monad m => ActionT m (IO ByteString) -- | Parse the request body as a JSON object and return it. -- -- If the JSON object is malformed, this sets the status to 400 Bad -- Request, and throws an exception. -- -- If the JSON fails to parse, this sets the status to 422 Unprocessable -- Entity. -- -- These status codes are as per -- https://www.restapitutorial.com/httpstatuscodes.html. jsonData :: (FromJSON a, MonadIO m) => ActionT m a -- | Get list of uploaded files. files :: Monad m => ActionT m [File] -- | Get a parameter. First looks in captures, then form data, then query -- parameters. -- -- -- | Deprecated: (#204) Not a good idea to treat all parameters -- identically. Use captureParam, formParam and queryParam instead. param :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Get all parameters from path, form and query (in that order). -- | Deprecated: (#204) Not a good idea to treat all parameters -- identically. Use pathParams, formParams and queryParams instead. params :: Monad m => ActionT m [Param] -- | Look up a path parameter. -- -- -- -- Since: 0.20 pathParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Synonym for pathParam captureParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Look up a form parameter. -- -- -- -- Since: 0.20 formParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Look up a query parameter. -- -- -- -- Since: 0.20 queryParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Look up a path parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions. In particular, route pattern matching -- will not continue, so developers must raiseStatus or -- throw to signal something went wrong. -- -- Since: 0.21 pathParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Look up a capture parameter. Returns Nothing if the parameter -- is not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions. In particular, route pattern matching -- will not continue, so developers must raiseStatus or -- throw to signal something went wrong. -- -- Since: 0.21 captureParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Look up a form parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions, so developers must raiseStatus -- or throw to signal something went wrong. -- -- Since: 0.21 formParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Look up a query parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions, so developers must raiseStatus -- or throw to signal something went wrong. -- -- Since: 0.21 queryParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Get path parameters pathParams :: Monad m => ActionT m [Param] -- | Get path parameters captureParams :: Monad m => ActionT m [Param] -- | Get form parameters formParams :: Monad m => ActionT m [Param] -- | Get query parameters queryParams :: Monad m => ActionT m [Param] -- | Set the HTTP response status. status :: MonadIO m => Status -> ActionT m () -- | Add to the response headers. Header names are case-insensitive. addHeader :: MonadIO m => Text -> Text -> ActionT m () -- | Set one of the response headers. Will override any previously set -- value for that header. Header names are case-insensitive. setHeader :: MonadIO m => Text -> Text -> ActionT m () -- | Redirect to given URL. Like throwing an uncatchable exception. Any -- code after the call to redirect will not be run. -- --
--   redirect "http://www.google.com"
--   
-- -- OR -- --
--   redirect "/foo/bar"
--   
redirect :: Monad m => Text -> ActionT m a text :: MonadIO m => Text -> ActionT m () html :: MonadIO m => Text -> ActionT 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. -- Setting a status code will have no effect because Warp will overwrite -- that to 200 (see sendResponse). file :: MonadIO m => FilePath -> ActionT m () -- | Set the body of the response to the JSON encoding of the given value. -- Also sets "Content-Type" header to "application/json; charset=utf-8" -- if it has not already been set. json :: (ToJSON a, MonadIO m) => a -> ActionT 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. stream :: MonadIO m => StreamingBody -> ActionT 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 :: MonadIO m => ByteString -> ActionT m () -- | Nest a whole WAI application inside a Scotty handler. See Web.Scotty -- for further documentation nested :: MonadIO m => Application -> ActionT m () -- | Access the HTTP headers of the Response -- -- SINCE 0.21 getResponseHeaders :: MonadIO m => ActionT m ResponseHeaders -- | Access the HTTP Status of the Response -- -- SINCE 0.21 getResponseStatus :: MonadIO m => ActionT m Status -- | Access the content of the Response -- -- SINCE 0.21 getResponseContent :: MonadIO m => ActionT m Content -- | Throw a "500 Server Error" StatusError, which can be caught -- with rescue. -- -- Uncaught exceptions turn into HTTP 500 responses. -- | Deprecated: Throw an exception instead raise :: MonadIO m => Text -> ActionT m a -- | Throw a StatusError exception that has an associated HTTP error -- code and can be caught with rescue. -- -- Uncaught exceptions turn into HTTP responses corresponding to the -- given status. -- | Deprecated: Use status, text, and finish instead raiseStatus :: Monad m => Status -> Text -> ActionT m a -- | Throw an exception which can be caught within the scope of the current -- Action with catch. -- -- If the exception is not caught locally, another option is to implement -- a global Handler (with defaultHandler) that defines -- its interpretation and a translation to HTTP error codes. -- -- Uncaught exceptions turn into HTTP 500 responses. throw :: (MonadIO m, Exception e) => e -> ActionT m a -- | Catch an exception e.g. a StatusError or a user-defined -- exception. -- --
--   raise JustKidding `catch` (\msg -> text msg)
--   
-- | Deprecated: Use catch instead rescue :: (MonadUnliftIO m, Exception e) => ActionT m a -> (e -> ActionT m a) -> ActionT m a -- | Abort execution of this action and continue pattern matching routes. -- Like an exception, any code after next is not executed. -- -- NB : Internally, this is implemented with an exception that can only -- be caught by the library, but not by the user. -- -- 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 <- pathParam "bar"
--     unless (w == "special") next
--     text "You made a request to /foo/special"
--   
--   get "/foo/:baz" $ do
--     w <- pathParam "baz"
--     text $ "You made a request to: " <> w
--   
next :: Monad m => ActionT m a -- | Finish the execution of the current action. Like throwing an -- uncatchable exception. Any code after the call to finish will not be -- run. -- -- Since: 0.10.3 finish :: Monad m => ActionT m a -- | Global handler for user-defined exceptions. defaultHandler :: Monad m => ErrorHandler m -> ScottyT m () -- | Catch any synchronous IO exceptions -- | Deprecated: Use liftIO instead liftAndCatchIO :: MonadIO m => IO a -> ActionT m a -- | Lift a computation from the IO monad. This allows us to run IO -- computations in any monadic stack, so long as it supports these kinds -- of operations (i.e. IO is the base monad for the stack). -- --

Example

-- --
--   import Control.Monad.Trans.State -- from the "transformers" library
--   
--   printState :: Show s => StateT s IO ()
--   printState = do
--     state <- get
--     liftIO $ print state
--   
-- -- Had we omitted liftIO, we would have ended up with -- this error: -- --
--   • Couldn't match type ‘IO’ with ‘StateT s IO’
--    Expected type: StateT s IO ()
--      Actual type: IO ()
--   
-- -- The important part here is the mismatch between StateT s IO -- () and IO (). -- -- Luckily, we know of a function that takes an IO a and -- returns an (m a): liftIO, enabling us to run -- the program and see the expected results: -- --
--   > evalStateT printState "hello"
--   "hello"
--   
--   > evalStateT printState 3
--   3
--   
liftIO :: MonadIO m => IO a -> m a -- | Catch a synchronous (but not asynchronous) exception and recover from -- it. -- -- This is parameterized on the exception type. To catch all synchronous -- exceptions, use catchAny. catch :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a -- | E.g. when a parameter is not found in a query string (400 Bad Request) -- or when parsing a JSON body fails (422 Unprocessable Entity) -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined data StatusError -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined StatusError :: Status -> Text -> StatusError -- | Thrown e.g. when a request is too large data ScottyException RequestTooLarge :: ScottyException MalformedJSON :: ByteString -> Text -> ScottyException FailedToParseJSON :: ByteString -> Text -> ScottyException PathParameterNotFound :: Text -> ScottyException QueryParameterNotFound :: Text -> ScottyException FormFieldNotFound :: Text -> ScottyException FailedToParseParameter :: Text -> Text -> Text -> ScottyException type Param = (Text, Text) -- | Minimum implemention: parseParam class Parsable a -- | Take a Text value and parse it as a, or fail with a -- message. parseParam :: Parsable a => Text -> Either Text a -- | Default implementation parses comma-delimited lists. -- --
--   parseParamList t = mapM parseParam (T.split (== ',') t)
--   
parseParamList :: Parsable a => Text -> Either Text [a] -- | Useful for creating Parsable instances for things that already -- implement Read. Ex: -- --
--   instance Parsable Int where parseParam = readEither
--   
readEither :: Read a => Text -> Either Text a data RoutePattern type File = (Text, FileInfo ByteString) data Content ContentBuilder :: Builder -> Content ContentFile :: FilePath -> Content ContentStream :: StreamingBody -> Content ContentResponse :: Response -> Content type Kilobytes = Int -- | Specializes a Handler to the ActionT monad type ErrorHandler m = Handler (ActionT m) () -- | Generalized version of Handler data Handler (m :: Type -> Type) a Handler :: (e -> m a) -> Handler (m :: Type -> Type) a data ScottyT m a data ActionT m a data ScottyState m defaultScottyState :: ScottyState m -- | This module is essentially identical to Trans, except that some -- functions take/return strict Text instead of the lazy ones. -- -- It should be noted that most of the code snippets below depend on the -- OverloadedStrings language pragma. -- -- The functions in this module allow an arbitrary monad to be embedded -- in Scotty's monad transformer stack in order that Scotty be combined -- with other DSLs. -- -- Scotty is set up by default for development mode. For production -- servers, you will likely want to modify settings and the -- defaultHandler. See the comments on each of these functions for -- more information. module Web.Scotty.Trans.Strict -- | Run a scotty application using the warp server. NB: scotty p === -- scottyT p id scottyT :: (Monad m, MonadIO n) => Port -> (m Response -> IO Response) -> ScottyT m () -> n () -- | Turn a scotty application into a WAI Application, which can be -- run with any WAI handler. NB: scottyApp === scottyAppT id scottyAppT :: (Monad m, Monad n) => (m Response -> IO Response) -> ScottyT m () -> n Application -- | Run a scotty application using the warp server, passing extra options. -- NB: scottyOpts opts === scottyOptsT opts id scottyOptsT :: (Monad m, MonadIO n) => Options -> (m Response -> IO Response) -> ScottyT m () -> n () -- | Run a scotty application using the warp server, passing extra options, -- and listening on the provided socket. NB: scottySocket opts sock === -- scottySocketT opts sock id scottySocketT :: (Monad m, MonadIO n) => Options -> Socket -> (m Response -> IO Response) -> ScottyT m () -> n () data Options Options :: Int -> Settings -> Options -- | 0 = silent, 1(def) = startup banner [verbose] :: Options -> Int -- | Warp Settings Note: to work around an issue in warp, the -- default FD cache duration is set to 0 so changes to static files are -- always picked up. This likely has performance implications, so you may -- want to modify this for production servers using -- setFdCacheDuration. [settings] :: Options -> Settings defaultOptions :: Options -- | 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 :: Middleware -> ScottyT m () -- | get = addroute GET get :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | post = addroute POST post :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | put = addroute PUT put :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | delete = addroute DELETE delete :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | patch = addroute PATCH patch :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | options = addroute OPTIONS options :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | Define a route with a StdMethod, a route pattern representing -- the path spec, and an Action which may modify the response. -- --
--   get "/" $ text "beam me up!"
--   
-- -- The path spec can include values starting with a colon, which are -- interpreted as captures. These are parameters that can be -- looked up with pathParam. -- --
--   >>> :{
--   let server = S.get "/foo/:bar" (S.pathParam "bar" >>= S.text)
--    in do
--         withScotty server $ curl "http://localhost:3000/foo/something"
--   :}
--   "something"
--   
addroute :: MonadUnliftIO m => StdMethod -> RoutePattern -> ActionT m () -> ScottyT m () -- | Add a route that matches regardless of the HTTP verb. matchAny :: MonadUnliftIO m => RoutePattern -> ActionT m () -> ScottyT m () -- | Specify an action to take if nothing else is found. Note: this -- _always_ matches, so should generally be the last route specified. notFound :: MonadUnliftIO m => ActionT m () -> ScottyT m () -- | Set global size limit for the request body. Requests with body size -- exceeding the limit will not be processed and an HTTP response 413 -- will be returned to the client. Size limit needs to be greater than 0, -- otherwise the application will terminate on start. setMaxRequestBodySize :: Kilobytes -> ScottyT m () -- | Standard Sinatra-style route. Named captures are prepended with -- colons. This is the default route type generated by OverloadedString -- routes. i.e. -- --
--   get (capture "/foo/:bar") $ ...
--   
-- -- and -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   ...
--   get "/foo/:bar" $ ...
--   
-- -- are equivalent. capture :: String -> RoutePattern -- | Match requests using a regular expression. Named captures are not yet -- supported. -- --
--   >>> :{
--   let server = S.get (S.regex "^/f(.*)r$") $ do
--                   cap <- S.pathParam "1"
--                   S.text cap
--    in do
--         withScotty server $ curl "http://localhost:3000/foo/bar"
--   :}
--   "oo/ba"
--   
regex :: String -> RoutePattern -- | Build a route based on a function which can match using the entire -- Request object. Nothing indicates the route does not -- match. A Just value indicates a successful match, optionally -- returning a list of key-value pairs accessible by param. -- --
--   >>> :{
--   let server = S.get (function $ \req -> Just [("version", T.pack $ show $ W.httpVersion req)]) $ do
--                   v <- S.pathParam "version"
--                   S.text v
--    in do
--         withScotty server $ curl "http://localhost:3000/"
--   :}
--   "HTTP/1.1"
--   
function :: (Request -> Maybe [Param]) -> RoutePattern -- | Build a route that requires the requested path match exactly, without -- captures. literal :: String -> RoutePattern -- | Get the Request object. request :: Monad m => ActionT m Request -- | Get a request header. Header name is case-insensitive. header :: Monad m => Text -> ActionT m (Maybe Text) -- | Get all the request headers. Header names are case-insensitive. headers :: Monad m => ActionT m [(Text, Text)] -- | Get the request body. body :: MonadIO m => ActionT m ByteString -- | Get an IO action that reads body chunks -- -- bodyReader :: Monad m => ActionT m (IO ByteString) -- | Get a parameter. First looks in captures, then form data, then query -- parameters. -- -- -- | Deprecated: (#204) Not a good idea to treat all parameters -- identically. Use captureParam, formParam and queryParam instead. param :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Get all parameters from path, form and query (in that order). -- | Deprecated: (#204) Not a good idea to treat all parameters -- identically. Use pathParams, formParams and queryParams instead. params :: Monad m => ActionT m [Param] -- | Synonym for pathParam captureParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Look up a form parameter. -- -- -- -- Since: 0.20 formParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Look up a query parameter. -- -- -- -- Since: 0.20 queryParam :: (Parsable a, MonadIO m) => Text -> ActionT m a -- | Look up a capture parameter. Returns Nothing if the parameter -- is not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions. In particular, route pattern matching -- will not continue, so developers must raiseStatus or -- throw to signal something went wrong. -- -- Since: 0.21 captureParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Look up a form parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions, so developers must raiseStatus -- or throw to signal something went wrong. -- -- Since: 0.21 formParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Look up a query parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions, so developers must raiseStatus -- or throw to signal something went wrong. -- -- Since: 0.21 queryParamMaybe :: (Parsable a, Monad m) => Text -> ActionT m (Maybe a) -- | Get path parameters captureParams :: Monad m => ActionT m [Param] -- | Get form parameters formParams :: Monad m => ActionT m [Param] -- | Get query parameters queryParams :: Monad m => ActionT m [Param] -- | Parse the request body as a JSON object and return it. -- -- If the JSON object is malformed, this sets the status to 400 Bad -- Request, and throws an exception. -- -- If the JSON fails to parse, this sets the status to 422 Unprocessable -- Entity. -- -- These status codes are as per -- https://www.restapitutorial.com/httpstatuscodes.html. jsonData :: (FromJSON a, MonadIO m) => ActionT m a -- | Get list of uploaded files. files :: Monad m => ActionT m [File] -- | Set the HTTP response status. status :: MonadIO m => Status -> ActionT m () -- | Add to the response headers. Header names are case-insensitive. addHeader :: MonadIO m => Text -> Text -> ActionT m () -- | Set one of the response headers. Will override any previously set -- value for that header. Header names are case-insensitive. setHeader :: MonadIO m => Text -> Text -> ActionT m () -- | Redirect to given URL. Like throwing an uncatchable exception. Any -- code after the call to redirect will not be run. -- --
--   redirect "http://www.google.com"
--   
-- -- OR -- --
--   redirect "/foo/bar"
--   
redirect :: Monad m => Text -> ActionT m a -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/plain; charset=utf-8" if it has not -- already been set. text :: MonadIO m => Text -> ActionT m () -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/html; charset=utf-8" if it has not -- already been set. html :: MonadIO m => Text -> ActionT 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. -- Setting a status code will have no effect because Warp will overwrite -- that to 200 (see sendResponse). file :: MonadIO m => FilePath -> ActionT m () -- | Set the body of the response to the JSON encoding of the given value. -- Also sets "Content-Type" header to "application/json; charset=utf-8" -- if it has not already been set. json :: (ToJSON a, MonadIO m) => a -> ActionT 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. stream :: MonadIO m => StreamingBody -> ActionT 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 :: MonadIO m => ByteString -> ActionT m () -- | Nest a whole WAI application inside a Scotty handler. See Web.Scotty -- for further documentation nested :: MonadIO m => Application -> ActionT m () -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/plain; charset=utf-8" if it has not -- already been set. textLazy :: MonadIO m => Text -> ActionT m () -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/html; charset=utf-8" if it has not -- already been set. htmlLazy :: MonadIO m => Text -> ActionT m () -- | Access the HTTP headers of the Response -- -- SINCE 0.21 getResponseHeaders :: MonadIO m => ActionT m ResponseHeaders -- | Access the HTTP Status of the Response -- -- SINCE 0.21 getResponseStatus :: MonadIO m => ActionT m Status -- | Access the content of the Response -- -- SINCE 0.21 getResponseContent :: MonadIO m => ActionT m Content -- | Throw a "500 Server Error" StatusError, which can be caught -- with catch. -- -- Uncaught exceptions turn into HTTP 500 responses. -- | Deprecated: Throw an exception instead raise :: MonadIO m => Text -> ActionT m a -- | Throw a StatusError exception that has an associated HTTP error -- code and can be caught with catch. -- -- Uncaught exceptions turn into HTTP responses corresponding to the -- given status. -- | Deprecated: Use status, text, and finish instead raiseStatus :: Monad m => Status -> Text -> ActionT m a -- | Throw an exception which can be caught within the scope of the current -- Action with catch. -- -- If the exception is not caught locally, another option is to implement -- a global Handler (with defaultHandler) that defines -- its interpretation and a translation to HTTP error codes. -- -- Uncaught exceptions turn into HTTP 500 responses. throw :: (MonadIO m, Exception e) => e -> ActionT m a -- | Catch an exception e.g. a StatusError or a user-defined -- exception. -- --
--   raise JustKidding `catch` (\msg -> text msg)
--   
-- | Deprecated: Use catch instead rescue :: (MonadUnliftIO m, Exception e) => ActionT m a -> (e -> ActionT m a) -> ActionT m a -- | Abort execution of this action and continue pattern matching routes. -- Like an exception, any code after next is not executed. -- -- NB : Internally, this is implemented with an exception that can only -- be caught by the library, but not by the user. -- -- 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 <- pathParam "bar"
--     unless (w == "special") next
--     text "You made a request to /foo/special"
--   
--   get "/foo/:baz" $ do
--     w <- pathParam "baz"
--     text $ "You made a request to: " <> w
--   
next :: Monad m => ActionT m a -- | Finish the execution of the current action. Like throwing an -- uncatchable exception. Any code after the call to finish will not be -- run. -- -- Since: 0.10.3 finish :: Monad m => ActionT m a -- | Global handler for user-defined exceptions. defaultHandler :: Monad m => ErrorHandler m -> ScottyT m () -- | Catch any synchronous IO exceptions -- | Deprecated: Use liftIO instead liftAndCatchIO :: MonadIO m => IO a -> ActionT m a -- | E.g. when a parameter is not found in a query string (400 Bad Request) -- or when parsing a JSON body fails (422 Unprocessable Entity) -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined data StatusError -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined StatusError :: Status -> Text -> StatusError -- | Thrown e.g. when a request is too large data ScottyException RequestTooLarge :: ScottyException MalformedJSON :: ByteString -> Text -> ScottyException FailedToParseJSON :: ByteString -> Text -> ScottyException PathParameterNotFound :: Text -> ScottyException QueryParameterNotFound :: Text -> ScottyException FormFieldNotFound :: Text -> ScottyException FailedToParseParameter :: Text -> Text -> Text -> ScottyException type Param = (Text, Text) -- | Minimum implemention: parseParam class Parsable a -- | Take a Text value and parse it as a, or fail with a -- message. parseParam :: Parsable a => Text -> Either Text a -- | Default implementation parses comma-delimited lists. -- --
--   parseParamList t = mapM parseParam (T.split (== ',') t)
--   
parseParamList :: Parsable a => Text -> Either Text [a] -- | Useful for creating Parsable instances for things that already -- implement Read. Ex: -- --
--   instance Parsable Int where parseParam = readEither
--   
readEither :: Read a => Text -> Either Text a data RoutePattern type File = (Text, FileInfo ByteString) data Content ContentBuilder :: Builder -> Content ContentFile :: FilePath -> Content ContentStream :: StreamingBody -> Content ContentResponse :: Response -> Content type Kilobytes = Int -- | Specializes a Handler to the ActionT monad type ErrorHandler m = Handler (ActionT m) () -- | Generalized version of Handler data Handler (m :: Type -> Type) a Handler :: (e -> m a) -> Handler (m :: Type -> Type) a data ScottyT m a data ActionT m a data ScottyState m defaultScottyState :: ScottyState m -- | It should be noted that most of the code snippets below depend on the -- OverloadedStrings language pragma. -- -- Scotty is set up by default for development mode. For production -- servers, you will likely want to modify settings and the -- defaultHandler. See the comments on each of these functions for -- more information. -- -- Please refer to the examples directory and the spec -- test suite for concrete use cases, e.g. constructing responses, -- exception handling and useful implementation details. module Web.Scotty -- | Run a scotty application using the warp server. scotty :: Port -> ScottyM () -> IO () -- | Run a scotty application using the warp server, passing extra options. scottyOpts :: Options -> ScottyM () -> IO () -- | Run a scotty application using the warp server, passing extra options, -- and listening on the provided socket. This allows the user to provide, -- for example, a Unix named socket, which can be used when reverse HTTP -- proxying into your application. scottySocket :: Options -> Socket -> ScottyM () -> IO () data Options Options :: Int -> Settings -> Options -- | 0 = silent, 1(def) = startup banner [verbose] :: Options -> Int -- | Warp Settings Note: to work around an issue in warp, the -- default FD cache duration is set to 0 so changes to static files are -- always picked up. This likely has performance implications, so you may -- want to modify this for production servers using -- setFdCacheDuration. [settings] :: Options -> Settings defaultOptions :: Options -- | Turn a scotty application into a WAI Application, which can be -- run with any WAI handler. scottyApp :: ScottyM () -> IO Application -- | 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 :: Middleware -> ScottyM () -- | get = addroute GET get :: RoutePattern -> ActionM () -> ScottyM () -- | post = addroute POST post :: RoutePattern -> ActionM () -> ScottyM () -- | put = addroute PUT put :: RoutePattern -> ActionM () -> ScottyM () -- | delete = addroute DELETE delete :: RoutePattern -> ActionM () -> ScottyM () -- | patch = addroute PATCH patch :: RoutePattern -> ActionM () -> ScottyM () -- | options = addroute OPTIONS options :: RoutePattern -> ActionM () -> ScottyM () -- | Define a route with a StdMethod, a route pattern representing -- the path spec, and an Action which may modify the response. -- --
--   get "/" $ text "beam me up!"
--   
-- -- The path spec can include values starting with a colon, which are -- interpreted as captures. These are parameters that can be -- looked up with pathParam. -- --
--   >>> :{
--   let server = S.get "/foo/:bar" (S.pathParam "bar" >>= S.text)
--    in do
--         withScotty server $ curl "http://localhost:3000/foo/something"
--   :}
--   "something"
--   
addroute :: StdMethod -> RoutePattern -> ActionM () -> ScottyM () -- | Add a route that matches regardless of the HTTP verb. matchAny :: RoutePattern -> ActionM () -> ScottyM () -- | Specify an action to take if nothing else is found. Note: this -- _always_ matches, so should generally be the last route specified. notFound :: ActionM () -> ScottyM () -- | Nest a whole WAI application inside a Scotty handler. Note: You will -- want to ensure that this route fully handles the response, as there is -- no easy delegation as per normal Scotty actions. Also, you will have -- to carefully ensure that you are expecting the correct routes, this -- could require stripping the current prefix, or adding the prefix to -- your application's handlers if it depends on them. One potential -- use-case for this is hosting a web-socket handler under a specific -- route. nested :: Application -> ActionM () -- | Set global size limit for the request body. Requests with body size -- exceeding the limit will not be processed and an HTTP response 413 -- will be returned to the client. Size limit needs to be greater than 0, -- otherwise the application will terminate on start. setMaxRequestBodySize :: Kilobytes -> ScottyM () -- | Standard Sinatra-style route. Named captures are prepended with -- colons. This is the default route type generated by OverloadedString -- routes. i.e. -- --
--   get (capture "/foo/:bar") $ ...
--   
-- -- and -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   ...
--   get "/foo/:bar" $ ...
--   
-- -- are equivalent. capture :: String -> RoutePattern -- | Match requests using a regular expression. Named captures are not yet -- supported. -- --
--   >>> :{
--   let server = S.get (S.regex "^/f(.*)r$") $ do
--                   cap <- S.pathParam "1"
--                   S.text cap
--    in do
--         withScotty server $ curl "http://localhost:3000/foo/bar"
--   :}
--   "oo/ba"
--   
regex :: String -> RoutePattern -- | Build a route based on a function which can match using the entire -- Request object. Nothing indicates the route does not -- match. A Just value indicates a successful match, optionally -- returning a list of key-value pairs accessible by param. -- --
--   >>> :{
--   let server = S.get (function $ \req -> Just [("version", T.pack $ show $ W.httpVersion req)]) $ do
--                   v <- S.pathParam "version"
--                   S.text v
--    in do
--         withScotty server $ curl "http://localhost:3000/"
--   :}
--   "HTTP/1.1"
--   
function :: (Request -> Maybe [Param]) -> RoutePattern -- | Build a route that requires the requested path match exactly, without -- captures. literal :: String -> RoutePattern -- | Get the Request object. request :: ActionM Request -- | Get a request header. Header name is case-insensitive. header :: Text -> ActionM (Maybe Text) -- | Get all the request headers. Header names are case-insensitive. headers :: ActionM [(Text, Text)] -- | Get the request body. body :: ActionM ByteString -- | Get an IO action that reads body chunks -- -- bodyReader :: ActionM (IO ByteString) -- | Parse the request body as a JSON object and return it. Raises an -- exception if parse is unsuccessful. jsonData :: FromJSON a => ActionM a -- | Get list of uploaded files. files :: ActionM [File] -- | Get a parameter. First looks in captures, then form data, then query -- parameters. -- -- -- | Deprecated: (#204) Not a good idea to treat all parameters -- identically. Use pathParam, formParam and queryParam instead. param :: Parsable a => Text -> ActionM a -- | Get all parameters from path, form and query (in that order). -- | Deprecated: (#204) Not a good idea to treat all parameters -- identically. Use pathParams, formParams and queryParams instead. params :: ActionM [Param] -- | Get a path parameter. -- -- -- -- Since: 0.21 pathParam :: Parsable a => Text -> ActionM a -- | Synonym for pathParam -- -- Since: 0.20 captureParam :: Parsable a => Text -> ActionM a -- | Get a form parameter. -- -- -- -- Since: 0.20 formParam :: Parsable a => Text -> ActionM a -- | Get a query parameter. -- -- -- -- Since: 0.20 queryParam :: Parsable a => Text -> ActionM a -- | Look up a path parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions. In particular, route pattern matching -- will not continue, so developers must raiseStatus or -- throw to signal something went wrong. -- -- Since: 0.21 pathParamMaybe :: Parsable a => Text -> ActionM (Maybe a) -- | Synonym for pathParamMaybe -- -- Since: 0.21 captureParamMaybe :: Parsable a => Text -> ActionM (Maybe a) -- | Look up a form parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions, so developers must raiseStatus -- or throw to signal something went wrong. -- -- Since: 0.21 formParamMaybe :: Parsable a => Text -> ActionM (Maybe a) -- | Look up a query parameter. Returns Nothing if the parameter is -- not found or cannot be parsed at the right type. -- -- NB : Doesn't throw exceptions, so developers must raiseStatus -- or throw to signal something went wrong. -- -- Since: 0.21 queryParamMaybe :: Parsable a => Text -> ActionM (Maybe a) -- | Get path parameters pathParams :: ActionM [Param] -- | Synonym for pathParams captureParams :: ActionM [Param] -- | Get form parameters formParams :: ActionM [Param] -- | Get query parameters queryParams :: ActionM [Param] -- | Set the HTTP response status. Default is 200. status :: Status -> ActionM () -- | Add to the response headers. Header names are case-insensitive. addHeader :: Text -> Text -> ActionM () -- | Set one of the response headers. Will override any previously set -- value for that header. Header names are case-insensitive. setHeader :: Text -> Text -> ActionM () -- | Redirect to given URL. Like throwing an uncatchable exception. Any -- code after the call to redirect will not be run. -- --
--   redirect "http://www.google.com"
--   
-- -- OR -- --
--   redirect "/foo/bar"
--   
redirect :: Text -> ActionM a -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/plain; charset=utf-8" if it has not -- already been set. text :: Text -> ActionM () -- | Set the body of the response to the given Text value. Also sets -- "Content-Type" header to "text/html; charset=utf-8" if it has not -- already been set. html :: Text -> ActionM () -- | 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 :: FilePath -> ActionM () -- | Set the body of the response to the JSON encoding of the given value. -- Also sets "Content-Type" header to "application/json; charset=utf-8" -- if it has not already been set. json :: ToJSON a => a -> ActionM () -- | Set the body of the response to a StreamingBody. Doesn't set the -- "Content-Type" header, so you probably want to do that on your own -- with setHeader. stream :: StreamingBody -> ActionM () -- | 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 :: ByteString -> ActionM () -- | Access the HTTP headers of the Response -- -- Since: 0.21 getResponseHeaders :: ActionM ResponseHeaders -- | Access the HTTP Status of the Response -- -- Since: 0.21 getResponseStatus :: ActionM Status -- | Access the content of the Response -- -- Since: 0.21 getResponseContent :: ActionM Content -- | Throw a "500 Server Error" StatusError, which can be caught -- with catch. -- -- Uncaught exceptions turn into HTTP 500 responses. -- | Deprecated: Throw an exception instead raise :: Text -> ActionM a -- | Throw a StatusError exception that has an associated HTTP error -- code and can be caught with catch. -- -- Uncaught exceptions turn into HTTP responses corresponding to the -- given status. -- | Deprecated: Use status, text, and finish instead raiseStatus :: Status -> Text -> ActionM a -- | Throw an exception which can be caught within the scope of the current -- Action with catch. -- -- If the exception is not caught locally, another option is to implement -- a global Handler (with defaultHandler) that defines its -- interpretation and a translation to HTTP error codes. -- -- Uncaught exceptions turn into HTTP 500 responses. throw :: Exception e => e -> ActionM a -- | Catch an exception e.g. a StatusError or a user-defined -- exception. -- --
--   raise JustKidding `catch` (\msg -> text msg)
--   
-- | Deprecated: Use catch instead rescue :: Exception e => ActionM a -> (e -> ActionM a) -> ActionM a -- | Abort execution of this action and continue pattern matching routes. -- Like an exception, any code after next is not executed. -- -- NB : Internally, this is implemented with an exception that can only -- be caught by the library, but not by the user. -- -- 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 <- pathParam "bar"
--     unless (w == "special") next
--     text "You made a request to /foo/special"
--   
--   get "/foo/:baz" $ do
--     w <- pathParam "baz"
--     text $ "You made a request to: " <> w
--   
next :: ActionM () -- | Abort execution of this action. Like an exception, any code after -- finish is not executed. -- -- As an example only requests to /foo/special will include in -- the response content the text message. -- --
--   get "/foo/:bar" $ do
--     w :: Text <- pathParam "bar"
--     unless (w == "special") finish
--     text "You made a request to /foo/special"
--   
-- -- Since: 0.10.3 finish :: ActionM a -- | Global handler for user-defined exceptions. defaultHandler :: ErrorHandler IO -> ScottyM () -- | Like liftIO, but catch any IO exceptions and turn them into -- Scotty exceptions. -- | Deprecated: Use liftIO instead liftAndCatchIO :: IO a -> ActionM a -- | Lift a computation from the IO monad. This allows us to run IO -- computations in any monadic stack, so long as it supports these kinds -- of operations (i.e. IO is the base monad for the stack). -- --

Example

-- --
--   import Control.Monad.Trans.State -- from the "transformers" library
--   
--   printState :: Show s => StateT s IO ()
--   printState = do
--     state <- get
--     liftIO $ print state
--   
-- -- Had we omitted liftIO, we would have ended up with -- this error: -- --
--   • Couldn't match type ‘IO’ with ‘StateT s IO’
--    Expected type: StateT s IO ()
--      Actual type: IO ()
--   
-- -- The important part here is the mismatch between StateT s IO -- () and IO (). -- -- Luckily, we know of a function that takes an IO a and -- returns an (m a): liftIO, enabling us to run -- the program and see the expected results: -- --
--   > evalStateT printState "hello"
--   "hello"
--   
--   > evalStateT printState 3
--   3
--   
liftIO :: MonadIO m => IO a -> m a -- | Catch a synchronous (but not asynchronous) exception and recover from -- it. -- -- This is parameterized on the exception type. To catch all synchronous -- exceptions, use catchAny. catch :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a -- | E.g. when a parameter is not found in a query string (400 Bad Request) -- or when parsing a JSON body fails (422 Unprocessable Entity) -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined data StatusError -- | Deprecated: If it is supposed to be caught, a proper exception type -- should be defined StatusError :: Status -> Text -> StatusError -- | Thrown e.g. when a request is too large data ScottyException RequestTooLarge :: ScottyException MalformedJSON :: ByteString -> Text -> ScottyException FailedToParseJSON :: ByteString -> Text -> ScottyException PathParameterNotFound :: Text -> ScottyException QueryParameterNotFound :: Text -> ScottyException FormFieldNotFound :: Text -> ScottyException FailedToParseParameter :: Text -> Text -> Text -> ScottyException type Param = (Text, Text) -- | Minimum implemention: parseParam class Parsable a -- | Take a Text value and parse it as a, or fail with a -- message. parseParam :: Parsable a => Text -> Either Text a -- | Default implementation parses comma-delimited lists. -- --
--   parseParamList t = mapM parseParam (T.split (== ',') t)
--   
parseParamList :: Parsable a => Text -> Either Text [a] -- | Useful for creating Parsable instances for things that already -- implement Read. Ex: -- --
--   instance Parsable Int where parseParam = readEither
--   
readEither :: Read a => Text -> Either Text a type ScottyM = ScottyT IO type ActionM = ActionT IO data RoutePattern type File = (Text, FileInfo ByteString) data Content ContentBuilder :: Builder -> Content ContentFile :: FilePath -> Content ContentStream :: StreamingBody -> Content ContentResponse :: Response -> Content type Kilobytes = Int -- | Specializes a Handler to the ActionT monad type ErrorHandler m = Handler (ActionT m) () -- | Generalized version of Handler data Handler (m :: Type -> Type) a Handler :: (e -> m a) -> Handler (m :: Type -> Type) a data ScottyState m defaultScottyState :: ScottyState m