From c1eb32b78550142acdb274e5a4662d9b99bf3f32 Mon Sep 17 00:00:00 2001 From: Marco Z Date: Sun, 17 Dec 2023 15:56:31 +0100 Subject: [PATCH] Docs and examples #341 (#358) * add docs and examples * make examples copypastable * links * stack exec example * examples links * haddock --------- Co-authored-by: Marco Zocca --- README.md | 39 +++++++++++++++++++++++++++++----- Web/Scotty.hs | 13 +++++++++--- Web/Scotty/Trans.hs | 15 +++++++++---- examples/basic.hs | 18 ++++++++++++---- examples/exceptions.hs | 9 ++++++-- examples/scotty-examples.cabal | 1 + 6 files changed, 77 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index c6785aea..bfe4e4ce 100644 --- a/README.md +++ b/README.md @@ -19,15 +19,44 @@ Scotty is the cheap and cheerful way to write RESTful, declarative web applicati * Conforms to the [web application interface (WAI)](https://github.com/yesodweb/wai/). * Uses the very fast Warp webserver by default. -See examples/basic.hs to see Scotty in action. (basic.hs needs the wai-extra package) +As for the name: Sinatra + Warp = Scotty. + +## Examples + +Run /basic.hs to see Scotty in action: ```bash -> runghc examples/basic.hs -Setting phasers to stun... (port 3000) (ctrl-c to quit) -(visit localhost:3000/somepath) +runghc examples/basic.hs ``` +`Setting phasers to stun... (port 3000) (ctrl-c to quit)` -As for the name: Sinatra + Warp = Scotty. +Or equivalently with [`stack`](https://docs.haskellstack.org/en/stable/): + +```bash +stack exec -- scotty-basic +``` + +Once the server is running you can interact with it with curl or a browser: + +```bash +curl localhost:3000 +``` +`foobar` + +```bash +curl localhost:3000/foo_query?p=42 +``` +`

42

` + + +Additionally, the `examples` directory shows a number of concrete use cases, e.g. + +* [exception handling](./examples/exceptions.hs) +* [global state](./examples/globalstate.hs) +* [configuration](./examples/reader.hs) +* [cookies](./examples/cookies.hs) +* [file upload](./examples/upload.hs) +* and more ## More Information diff --git a/Web/Scotty.hs b/Web/Scotty.hs index 5317f085..deced828 100644 --- a/Web/Scotty.hs +++ b/Web/Scotty.hs @@ -5,9 +5,16 @@ -- Scotty is set up by default for development mode. For production servers, -- you will likely want to modify 'Trans.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 - ( -- * scotty-to-WAI - scotty, scottyApp, scottyOpts, scottySocket, Options(..), defaultOptions + ( -- * Running 'scotty' servers + scotty + , scottyOpts + , scottySocket + , Options(..), defaultOptions + -- ** scotty-to-WAI + , scottyApp -- * Defining Middleware and Routes -- -- | 'Middleware' and routes are run in the order in which they @@ -40,7 +47,7 @@ module Web.Scotty -- * Parsing Parameters , Param, Trans.Parsable(..), Trans.readEither -- * Types - , ScottyM, ActionM, RoutePattern, File, Content(..), Kilobytes, Handler(..) + , ScottyM, ActionM, RoutePattern, File, Content(..), Kilobytes, ErrorHandler, Handler(..) , ScottyState, defaultScottyState ) where diff --git a/Web/Scotty/Trans.hs b/Web/Scotty/Trans.hs index 117accad..d78eda3b 100644 --- a/Web/Scotty/Trans.hs +++ b/Web/Scotty/Trans.hs @@ -4,15 +4,22 @@ -- 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. +-- 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 - ( -- * scotty-to-WAI - scottyT, scottyAppT, scottyOptsT, scottySocketT, Options(..), defaultOptions + ( -- * Running 'scotty' servers + scottyT + , scottyOptsT + , scottySocketT + , Options(..), defaultOptions + -- ** scotty-to-WAI + , scottyAppT -- * Defining Middleware and Routes -- -- | 'Middleware' and routes are run in the order in which they diff --git a/examples/basic.hs b/examples/basic.hs index c489bdfd..3c2c33ce 100644 --- a/examples/basic.hs +++ b/examples/basic.hs @@ -35,10 +35,20 @@ main = scotty 3000 $ do get "/" $ text "foobar" get "/" $ text "barfoo" - -- Using a parameter in the query string. Since it has - -- not been given, a 500 page is generated. - get "/foo" $ do - v <- pathParam "fooparam" + -- Looking for a parameter in the path. Since the path pattern does not + -- contain the parameter name 'p', the server responds with 500 Server Error. + get "/foo_fail" $ do + v <- pathParam "p" + html $ mconcat ["

", v, "

"] + + -- Looking for a parameter 'p' in the path. + get "/foo_path/:p" $ do + v <- pathParam "p" + html $ mconcat ["

", v, "

"] + + -- Looking for a parameter 'p' in the query string. + get "/foo_query" $ do + v <- queryParam "p" html $ mconcat ["

", v, "

"] -- An uncaught error becomes a 500 page. diff --git a/examples/exceptions.hs b/examples/exceptions.hs index 4faf1a69..6bf050c2 100644 --- a/examples/exceptions.hs +++ b/examples/exceptions.hs @@ -5,6 +5,7 @@ module Main (main) where import Control.Exception (Exception(..)) import Control.Monad.IO.Class +import Control.Monad.IO.Unlift (MonadUnliftIO(..)) import Data.String (fromString) import Data.Typeable @@ -34,8 +35,12 @@ handleEx = Handler $ \case html $ fromString $ "

" ++ s ++ "

" main :: IO () -main = scottyT 3000 id $ do -- note, we aren't using any additional transformer layers - -- so we can just use 'id' for the runner. +main = do + scottyT 3000 id server -- note: we use 'id' since we don't have to run any effects at each action + +-- Any custom monad stack will need to implement 'MonadUnliftIO' +server :: MonadUnliftIO m => ScottyT m () +server = do middleware logStdoutDev defaultHandler handleEx -- define what to do with uncaught exceptions diff --git a/examples/scotty-examples.cabal b/examples/scotty-examples.cabal index 47b44214..3a4fe64f 100644 --- a/examples/scotty-examples.cabal +++ b/examples/scotty-examples.cabal @@ -66,6 +66,7 @@ executable scotty-exceptions random, scotty, transformers, + unliftio-core, wai-extra GHC-options: -Wall -threaded