Continue consolidating API into single module

This commit is contained in:
Rashad Gover 2022-08-30 07:54:04 +00:00
parent a6370f5ac4
commit bd6c9fc43e
9 changed files with 626 additions and 595 deletions

View File

@ -29,7 +29,7 @@ import qualified Web.HttpApiData as Web
(??) action queryItemName =
action >> do
flag <- queryFlag queryItemName
if flag then pure () else skip
if flag then pure () else next
(?:) :: forall m a. MonadOkapi m => m a -> Text.Text -> m ()
(?:) = undefined -- This should be the query param version of

View File

@ -58,7 +58,7 @@ module Okapi.Parser
-- | Various helper functions for throwing parser errors
-- See for more information on how throwing error works
skip,
next,
throw,
(<!>),
guardThrow,
@ -213,7 +213,7 @@ method method = do
method' <- parseMethod
if method == method'
then pure ()
else skip
else next
-- | Parses and discards a single path segment matching the given @Text@ value
--
@ -263,7 +263,7 @@ path = mapM_ pathSeg
pathParam :: forall a m. (MonadOkapi m, Web.FromHttpApiData a) => m a
pathParam = do
pathSeg <- parsePathSeg
maybe skip pure (Web.parseUrlPieceMaybe pathSeg)
maybe next pure (Web.parseUrlPieceMaybe pathSeg)
-- | Parses a single path segment as raw @Text@.
-- Use this instead of @pathParam@ if you want to process the path segment yourself
@ -305,14 +305,14 @@ pathSegWith predicate = do
pathSeg <- parsePathSeg
if predicate pathSeg
then pure ()
else skip
else next
-- | Parses all the remaining path segments of a request
pathWildcard :: forall m. MonadOkapi m => m (NonEmpty.NonEmpty Text.Text)
pathWildcard = do
segs <- some pathParamRaw
case segs of
[] -> skip
[] -> next
_ -> pure $ NonEmpty.fromList segs
-- QUERY HELPERS
@ -340,8 +340,8 @@ queryParam :: forall a m. (MonadOkapi m, Web.FromHttpApiData a) => Text.Text ->
queryParam queryItemName = do
(_, queryItemValue) <- parseQueryItem queryItemName
case queryItemValue of
QueryFlag -> skip
QueryParam valueText -> maybe skip pure (Web.parseQueryParamMaybe valueText)
QueryFlag -> next
QueryParam valueText -> maybe next pure (Web.parseQueryParamMaybe valueText)
-- | Parses the value of a query parameter as raw @Text@.
-- Use this instead of @queryParam@ if you want to process the query parameter yourself
@ -373,7 +373,7 @@ queryParamRaw :: forall m. MonadOkapi m => Text.Text -> m Text.Text
queryParamRaw queryItemName = do
(_, queryItemValue) <- parseQueryItem queryItemName
case queryItemValue of
QueryFlag -> skip
QueryFlag -> next
QueryParam raw -> pure raw
-- | Test for the existance of a query flag
@ -416,12 +416,12 @@ basicAuth = do
case Text.words $ Text.decodeUtf8 authValue of
["Basic", encodedCreds] ->
case decodeBase64 encodedCreds of
Left _ -> skip
Left _ -> next
Right decodedCreds ->
case Text.split (== ':') decodedCreds of
[userID, password] -> pure (userID, password)
_ -> skip
_ -> skip
_ -> next
_ -> next
-- TODO: cookie :: forall m. MonadOkapi m => Cookie
@ -446,12 +446,12 @@ header headerName = do
bodyJSON :: forall a m. (MonadOkapi m, Aeson.FromJSON a) => m a
bodyJSON = do
body <- bodyRaw
maybe skip pure (Aeson.decode body)
maybe next pure (Aeson.decode body)
bodyForm :: forall a m. (MonadOkapi m, Web.FromForm a) => m a
bodyForm = do
body <- bodyRaw
maybe skip pure (eitherToMaybe $ Web.urlDecodeAsForm body)
maybe next pure (eitherToMaybe $ Web.urlDecodeAsForm body)
where
eitherToMaybe :: Either l r -> Maybe r
eitherToMaybe either = case either of
@ -469,14 +469,14 @@ respond response = do
check1 <- methodParsed
check2 <- pathParsed
-- check3 <- queryParsed
if check1 && check2 then return response else skip
if check1 && check2 then return response else next
-- TODO: add end parser similar to <https://github.com/purescript-contrib/purescript-routing/blob/main/GUIDE.md>
-- Error HELPERS
skip :: forall a m. MonadOkapi m => m a
skip = Except.throwError Skip
next :: forall a m. MonadOkapi m => m a
next = Except.throwError Skip
throw :: forall a m. MonadOkapi m => Response -> m a
throw = Except.throwError . Error
@ -521,7 +521,7 @@ parseMethod :: MonadOkapi m => m HTTP.Method
parseMethod = do
isMethodParsed <- methodParsed
if isMethodParsed
then skip
then next
else do
method <- State.gets (requestMethod . stateRequest)
State.modify (\state -> state {stateRequestMethodParsed = True})
@ -534,7 +534,7 @@ parsePathSeg :: MonadOkapi m => m Text.Text
parsePathSeg = do
maybePathSeg <- State.gets (safeHead . requestPath . stateRequest)
case maybePathSeg of
Nothing -> skip
Nothing -> next
Just pathSeg -> do
State.modify (\state -> state {stateRequest = (stateRequest state) {requestPath = Prelude.drop 1 $ requestPath $ stateRequest state}})
pure pathSeg
@ -547,7 +547,7 @@ parseQueryItem :: MonadOkapi m => Text.Text -> m QueryItem
parseQueryItem queryItemName = do
maybeQueryItem <- State.gets (Foldable.find (\(queryItemName', _) -> queryItemName == queryItemName') . requestQuery . stateRequest)
case maybeQueryItem of
Nothing -> skip
Nothing -> next
Just queryItem -> do
State.modify (\state -> state {stateRequest = (stateRequest state) {requestQuery = List.delete queryItem $ requestQuery $ stateRequest state}})
pure queryItem
@ -568,7 +568,7 @@ parseHeader :: MonadOkapi m => HTTP.HeaderName -> m Header
parseHeader headerName = do
maybeHeader <- State.gets (Foldable.find (\(headerName', _) -> headerName == headerName') . requestHeaders . stateRequest)
case maybeHeader of
Nothing -> skip
Nothing -> next
Just header -> do
State.modify (\state -> state {stateRequest = (stateRequest state) {requestHeaders = List.delete header $ requestHeaders $ stateRequest state}})
pure header
@ -577,7 +577,7 @@ parseBody :: forall m. MonadOkapi m => m LBS.ByteString
parseBody = do
isBodyParsed <- bodyParsed
if isBodyParsed
then skip
then next
else do
body <- State.gets (requestBody . stateRequest)
State.modify (\state -> state {stateRequestBodyParsed = True})
@ -605,10 +605,10 @@ static
-}
lookupQuery :: MonadOkapi m => Text -> Query -> m QueryValue
lookupQuery name query = maybe skip pure (List.lookup name query)
lookupQuery name query = maybe next pure (List.lookup name query)
lookupHeaders :: MonadOkapi m => HeaderName -> Headers -> m BS.ByteString
lookupHeaders name headers = maybe skip pure (List.lookup name headers)
lookupHeaders name headers = maybe next pure (List.lookup name headers)
lookupForm :: (MonadOkapi m, Web.FromHttpApiData a) => Text -> Body -> m a
lookupForm = undefined

View File

@ -169,4 +169,4 @@ getRawURL = undefined
-- match :: MonadOkapi m => Pattern a -> m a
-- match pattern = do
-- rawURL <- getRawURL
-- maybe skip return (matcher pattern rawURL)
-- maybe next return (matcher pattern rawURL)

View File

@ -106,7 +106,7 @@ testMatcher = matchWith $ \case
BlogRoute -> respond ok
BlogRouteId blogID -> respond ok
BlogRouteIdSection blogID sectionName -> respond ok
_ -> Okapi.skip
_ -> Okapi.next
testPattern :: (Pattern -> Bool) -> Pattern -> Bool
testPattern f = f

View File

@ -169,7 +169,7 @@ testMatcher = matchWith $ \case
BlogRouteId blogID -> respond ok
BlogRouteIdSection blogID sectionName -> respond ok
BlogQueryRoute author category -> respond ok
_ -> Okapi.skip
_ -> Okapi.next
testPattern :: (Pattern -> Bool) -> Pattern -> Bool
testPattern f = f

View File

@ -29,6 +29,29 @@ import qualified Data.Vault.Lazy as Vault
import qualified GHC.Natural as Natural
import qualified Network.HTTP.Types as HTTP
{-
TODO: HTTPDataStore? Not really needed because you can just pass data normally or store in own monad.
One benefit is that the data is available to all sub-branches without explicitly passing them to every sub-branch.
-- This data structure should be hidden from user
data HTTPDataStore = HTTPDataStore
{ pathStore :: (Map Text Text)
, queryStore :: (Map Text Text)
, headerStore :: (Map Text Text)
}
-- Can only store parsed information
storePathParam :: forall a. FromHttpApiData a => Text -> Okapi a
storePathParam = ...
storeQueryParam :: ... => Text -> Okapi a
storeHeader :: ... => Text -> Okapi a
-- Can fail on Map lookup and data conversion
findPathParam :: forall a. FromHttpApiData a => Okapi a
-}
type MonadOkapi m =
( Functor m,
Applicative m,

File diff suppressed because it is too large Load Diff

View File

@ -120,7 +120,7 @@ routePartsToExp [] =
pure $
RecConE
(mkName "Route")
[ (mkName "parser", VarE (mkName "Okapi.skip")),
[ (mkName "parser", VarE (mkName "Okapi.next")),
(mkName "url", LamE [VarP $ mkName "unit"] (AppE (ConE $ mkName "Okapi.URL") (LitE $ StringL "")))
]
routePartsToExp routeParts = do
@ -183,7 +183,7 @@ routePartStmtAndBinding rp = case rp of
"DELETE" -> pure (Nothing, Nothing, NoBindS (VarE $ mkName "Okapi.delete"))
"PUT" -> pure (Nothing, Nothing, NoBindS (VarE $ mkName "Okapi.put"))
"PATCH" -> pure (Nothing, Nothing, NoBindS (VarE $ mkName "Okapi.patch"))
_ -> pure (Nothing, Nothing, NoBindS (VarE $ mkName "Okapi.skip"))
_ -> pure (Nothing, Nothing, NoBindS (VarE $ mkName "Okapi.next"))
PathSegMatch txt -> pure (Nothing, Just $ PathSegType txt, NoBindS (AppE (VarE $ mkName "Okapi.pathSeg") (LitE $ StringL $ unpack txt)))
AnonPathSeg (CurlyExpr typeName functionNamesToApply maybeGuardFunction) -> do
stmtBinding <- runIO randName

View File

@ -225,7 +225,7 @@ testMatcher = match $ \case
BlogIDRoute blogID -> respond ok
BlogIDSectionRoute blogID sectionName -> respond ok
BlogQueryRoute author category -> respond ok
_ -> Okapi.skip
_ -> Okapi.next
testPattern :: (Okapi.Request -> Bool) -> Okapi.Request -> Bool
testPattern f = f