Skip to content

Commit

Permalink
add captureParamMaybe, queryParamMaybe, formParamMaybe (#322)
Browse files Browse the repository at this point in the history
* expose new functions and add test

* haddocks

* more readable test for captureParamMaybe

* changelog entry

---------

Co-authored-by: Marco Zocca <[email protected]>
  • Loading branch information
ocramz and Marco Zocca authored Oct 10, 2023
1 parent 99a602b commit 1517d23
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 3 deletions.
36 changes: 36 additions & 0 deletions Web/Scotty.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module Web.Scotty
, request, header, headers, body, bodyReader
, param, params
, captureParam, formParam, queryParam
, captureParamMaybe, formParamMaybe, queryParamMaybe
, captureParams, formParams, queryParams
, jsonData, files
-- ** Modifying the Response and Redirecting
Expand Down Expand Up @@ -228,6 +229,8 @@ param = Trans.param
-- * Raises an exception which can be caught by 'rescue' if parameter is not found. If the exception is not caught, scotty will return a HTTP error code 500 ("Internal Server Error") to the client.
--
-- * If the parameter is found, but 'parseParam' fails to parse to the correct type, 'next' is called.
--
-- /Since: 0.20/
captureParam :: Trans.Parsable a => Text -> ActionM a
captureParam = Trans.captureParam

Expand All @@ -236,6 +239,8 @@ captureParam = Trans.captureParam
-- * Raises an exception which can be caught by 'rescue' if parameter is not found. If the exception is not caught, scotty will return a HTTP error code 400 ("Bad Request") to the client.
--
-- * This function raises a code 400 also if the parameter is found, but 'parseParam' fails to parse to the correct type.
--
-- /Since: 0.20/
formParam :: Trans.Parsable a => Text -> ActionM a
formParam = Trans.formParam

Expand All @@ -244,9 +249,40 @@ formParam = Trans.formParam
-- * Raises an exception which can be caught by 'rescue' if parameter is not found. If the exception is not caught, scotty will return a HTTP error code 400 ("Bad Request") to the client.
--
-- * This function raises a code 400 also if the parameter is found, but 'parseParam' fails to parse to the correct type.
--
-- /Since: 0.20/
queryParam :: Trans.Parsable a => Text -> ActionM a
queryParam = Trans.queryParam


-- | 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: FIXME/
captureParamMaybe :: (Trans.Parsable a) => Text -> ActionM (Maybe a)
captureParamMaybe = Trans.captureParamMaybe

-- | 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: FIXME/
formParamMaybe :: (Trans.Parsable a) => Text -> ActionM (Maybe a)
formParamMaybe = Trans.formParamMaybe

-- | 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: FIXME/
queryParamMaybe :: (Trans.Parsable a) => Text -> ActionM (Maybe a)
queryParamMaybe = Trans.queryParamMaybe




-- | Get all parameters from capture, form and query (in that order).
params :: ActionM [Param]
params = Trans.params

Check warning on line 288 in Web/Scotty.hs

View workflow job for this annotation

GitHub Actions / ubuntu-latest / ghc 8.10.7

In the use of ‘params’

Check warning on line 288 in Web/Scotty.hs

View workflow job for this annotation

GitHub Actions / ubuntu-latest / ghc 9.0.2

In the use of ‘params’

Check warning on line 288 in Web/Scotty.hs

View workflow job for this annotation

GitHub Actions / ubuntu-latest / ghc 9.2.8

In the use of ‘params’

Check warning on line 288 in Web/Scotty.hs

View workflow job for this annotation

GitHub Actions / ubuntu-latest / ghc 9.4.6

In the use of ‘params’

Check warning on line 288 in Web/Scotty.hs

View workflow job for this annotation

GitHub Actions / ubuntu-latest / ghc 9.6.2

In the use of ‘params’
Expand Down
56 changes: 53 additions & 3 deletions Web/Scotty/Action.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ module Web.Scotty.Action
, captureParam
, formParam
, queryParam
, captureParamMaybe
, formParamMaybe
, queryParamMaybe
, params
, captureParams
, formParams
Expand Down Expand Up @@ -282,30 +285,62 @@ param k = do
Just v -> either (const next) return $ parseParam v
{-# DEPRECATED param "(#204) Not a good idea to treat all parameters identically. Use captureParam, formParam and queryParam instead. "#-}

-- | Get a capture parameter.
-- | Look up a capture parameter.
--
-- * Raises an exception which can be caught by 'rescue' if parameter is not found. If the exception is not caught, scotty will return a HTTP error code 500 ("Internal Server Error") to the client.
--
-- * If the parameter is found, but 'parseParam' fails to parse to the correct type, 'next' is called.
--
-- /Since: 0.20/
captureParam :: (Parsable a, Monad m) => T.Text -> ActionT m a
captureParam = paramWith CaptureParam envCaptureParams status500

-- | Get a form parameter.

-- | Look up a form parameter.
--
-- * Raises an exception which can be caught by 'rescue' if parameter is not found. If the exception is not caught, scotty will return a HTTP error code 400 ("Bad Request") to the client.
--
-- * This function raises a code 400 also if the parameter is found, but 'parseParam' fails to parse to the correct type.
--
-- /Since: 0.20/
formParam :: (Parsable a, Monad m) => T.Text -> ActionT m a
formParam = paramWith FormParam envFormParams status400

-- | Get a query parameter.
-- | Look up a query parameter.
--
-- * Raises an exception which can be caught by 'rescue' if parameter is not found. If the exception is not caught, scotty will return a HTTP error code 400 ("Bad Request") to the client.
--
-- * This function raises a code 400 also if the parameter is found, but 'parseParam' fails to parse to the correct type.
--
-- /Since: 0.20/
queryParam :: (Parsable a, Monad m) => T.Text -> ActionT m a
queryParam = paramWith QueryParam envQueryParams status400

-- | 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: FIXME/
captureParamMaybe :: (Parsable a, Monad m) => T.Text -> ActionT m (Maybe a)
captureParamMaybe = paramWithMaybe envCaptureParams

-- | 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: FIXME/
formParamMaybe :: (Parsable a, Monad m) => T.Text -> ActionT m (Maybe a)
formParamMaybe = paramWithMaybe envFormParams

-- | 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: FIXME/
queryParamMaybe :: (Parsable a, Monad m) => T.Text -> ActionT m (Maybe a)
queryParamMaybe = paramWithMaybe envQueryParams

data ParamType = CaptureParam
| FormParam
| QueryParam
Expand All @@ -331,6 +366,21 @@ paramWith ty f err k = do
_ -> raiseStatus err (T.unwords ["Cannot parse", v, "as a", T.pack (show ty), "parameter"])
in either (const $ handleParseError ty) return $ parseParam v

-- | Look up a parameter. Returns 'Nothing' if the parameter is not found or cannot be parsed at the right type.
--
-- NB : Doesn't throw exceptions.
--
-- /Since: FIXME/
paramWithMaybe :: (Monad m, Parsable b) =>
(ActionEnv -> [Param])
-> T.Text -- ^ parameter name
-> ActionT m (Maybe b)
paramWithMaybe f k = do
val <- ActionT $ (lookup k . f) <$> ask
case val of
Nothing -> pure Nothing
Just v -> either (const $ pure Nothing) (pure . Just) $ parseParam v

-- | Get all parameters from capture, form and query (in that order).
params :: Monad m => ActionT m [Param]
params = paramsWith getParams
Expand Down
1 change: 1 addition & 0 deletions Web/Scotty/Trans.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module Web.Scotty.Trans
, request, header, headers, body, bodyReader
, param, params
, captureParam, formParam, queryParam
, captureParamMaybe, formParamMaybe, queryParamMaybe
, captureParams, formParams, queryParams
, jsonData, files
-- ** Modifying the Response and Redirecting
Expand Down
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## next [????.??.??]

* add getResponseHeaders, getResponseStatus, getResponseContent (#214)
* add `captureParamMaybe`, `formParamMaybe`, `queryParamMaybe` (#322)

## 0.20.1 [2023.10.03]

Expand All @@ -9,6 +10,7 @@
* re-add MonadError (ActionT m) instance, but the error type is now specialized to 'StatusError' (#325)
* raise lower bound on base ( > 4.14 ) to reflect support for GHC >= 8.10 (#325).


## 0.20 [2023.10.02]
* Drop support for GHC < 8.10 and modernise the CI pipeline (#300).
* Adds a new `nested` handler that allows you to place an entire WAI Application under a Scotty route (#233).
Expand Down
20 changes: 20 additions & 0 deletions test/Web/ScottySpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,26 @@ spec = do
it "catches a StatusError" $ do
postForm "/search" "z=potato" `shouldRespondWith` 200 { matchBody = "z"}

describe "captureParamMaybe" $ do
withApp (
do
Scotty.get "/a/:q" $ do
mx <- captureParamMaybe "q"
case mx of
Just (_ :: Int) -> status status200
Nothing -> status status500
Scotty.get "/b/:q" $ do
mx <- captureParamMaybe "z"
case mx of
Just (_ :: TL.Text) -> text "impossible" >> status status500
Nothing -> status status200
) $ do
it "responds with 200 OK if the parameter can be parsed at the right type, 500 otherwise" $ do
get "/a/potato" `shouldRespondWith` 500
get "/a/42" `shouldRespondWith` 200
it "responds with 200 OK if the parameter is not found" $ do
get "/b/potato" `shouldRespondWith` 200


describe "text" $ do
let modernGreekText :: IsString a => a
Expand Down

0 comments on commit 1517d23

Please sign in to comment.