Skip to content

Commit cb36f6f

Browse files
committed
Merge branch 'master' of github.com:byteally/webapi
2 parents 2fc45dd + 7891e69 commit cb36f6f

File tree

12 files changed

+1882
-49
lines changed

12 files changed

+1882
-49
lines changed

cabal.project

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,18 @@ packages:
33
webapi-contract
44
webapi
55
webapi-client-reflex-dom
6-
webapi-swagger
6+
-- webapi-swagger
77
webapi-docs
88
webapi-xml
9-
webapi-openapi
9+
-- webapi-openapi
1010
webapi-reflex-dom
11+
webapi-test
12+
-- ../rec/rec
13+
14+
source-repository-package
15+
type: git
16+
location: https://github.com/byteally/rec
17+
tag: 6deffbca324faca6c2c6ded28c38fea8f5edd716
18+
subdir: rec
19+
20+
allow-newer: typerep-map:base, typerep-map:ghc-prim

webapi-client-reflex-dom/src/WebApi/Client/Reflex.hs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -171,27 +171,29 @@ clientOrigin baseUrl reqEvt = do
171171
-- TODO: Handle other xhr response case
172172
xhrResp = LBS.fromStrict $ T.encodeUtf8 $ maybe T.empty id $ _xhrResponse_responseText resp
173173

174-
in case WebApi.Success <$> pure status
175-
<*> (Validation $ toParamErr $ decode' (Res :: Resource meth r) xhrResp)
176-
<*> respHdr
177-
<*> pure () of
178-
Validation (Right success) -> success
179-
Validation (Left errs1) ->
180-
case ApiError
181-
<$> pure status
182-
<*> (Validation $ toParamErr $ decode' (Res :: Resource meth r) xhrResp)
183-
<*> (Just <$> respHdr)
184-
<*> (Just <$> (pure ())) of
185-
Validation (Right failure) -> (WebApi.Failure . Left) failure
186-
Validation (Left errs2) ->
187-
let errs = case HT.statusCode status of
188-
200 -> errs1
189-
_ -> errs2
190-
in WebApi.Failure $ Right (OtherError (toException $ ApiErrParseFailException status $ T.intercalate "\n" $ fmap (T.pack . show) errs))
174+
in
175+
case statusIsSuccessful status of
176+
True ->
177+
let res = WebApi.Success <$> pure status
178+
<*> (Validation $ toParamErr $ decode' (Res :: Resource meth r) xhrResp)
179+
<*> respHdr
180+
<*> pure ()
181+
in case res of
182+
Validation (Right success) -> success
183+
Validation (Left errs) -> WebApi.Failure $ Right (OtherError (toException $ ApiErrParseFailException status $ T.intercalate "\n" $ fmap (T.pack . show) errs))
184+
False ->
185+
let res = ApiError
186+
<$> pure status
187+
<*> (Validation $ toParamErr $ decode' (Res :: Resource meth r) xhrResp)
188+
<*> (Just <$> respHdr)
189+
<*> (Just <$> (pure ()))
190+
in case res of
191+
Validation (Right failure) -> (WebApi.Failure . Left) failure
192+
Validation (Left errs) -> WebApi.Failure $ Right (OtherError (toException $ ApiErrParseFailException status $ T.intercalate "\n" $ fmap (T.pack . show) errs))
191193

192194
pure $ ffor xhrRes $ \case
193195
Left e -> WebApi.Failure $ Right $ OtherError $ toException e
194-
Right r -> fromClientResponse r
196+
Right r -> fromClientResponse r
195197

196198
data ContentDecodeException
197199
= ContentDecodeException

webapi-reflex-dom/src/WebApi/Reflex/Dom/Router.hs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ data Dom m
8989
instance SingMethod m => SingMethod (Dom m) where
9090
singMethod _ = singMethod (Proxy :: Proxy m)
9191

92-
class WebUIServer (s :: *) where
93-
type UIInterface s :: *
92+
class WebUIServer (s :: Type) where
93+
type UIInterface s :: Type
9494
type UIInterface s = s
9595

96-
class UIHandler w (t :: *) s m r where
96+
class UIHandler w (t :: Type) s m r where
9797
handler :: s -> Dynamic t (Request m r) -> w (Response m r)
9898

9999
newtype UIRequestRep =
@@ -104,7 +104,7 @@ compactUIServer :: forall api m server t. server t (RouteT t m) -> CompactUIServ
104104
compactUIServer = CompactUIServer
105105

106106
mkUIRequestRep ::
107-
forall route (m :: *) (r :: *).
107+
forall route (m :: Type) (r :: Type).
108108
( Typeable m
109109
, Typeable r
110110
) => route m r -> UIRequestRep
@@ -122,10 +122,10 @@ data DomResponse =
122122

123123
type ReflexDomApplication t m = (UIRequestRep -> Event t DomRequest) -> Dynamic t DomRequest -> DomRequest -> RouteResult (UIRequestRep, m (Event t DomResponse))
124124

125-
class Monad w => Router (w :: * -> *) (t :: *) (server :: *) (r :: k) (pr :: (*, [*])) where
125+
class Monad w => Router (w :: Type -> Type) (t :: Type) (server :: Type) (r :: k) (pr :: (Type, [Type])) where
126126
route :: Proxy '(r, t) -> server -> ParsedRoute t pr -> (Dynamic t [ParamErr] -> w ()) -> ReflexDomApplication t w
127127

128-
instance ( SingMethod (m :: *)
128+
instance ( SingMethod (m :: Type)
129129
, Router w t s r '(Dom m, '[])
130130
, MonadWidget t w
131131
) => Router w t s (W.Route '[Dom m] r) pr where
@@ -139,7 +139,7 @@ instance
139139
( Router w t s route pr
140140
, Router w t s routes pr
141141
, Reflex t
142-
) => Router w t s ((route :: *) ': routes) pr where
142+
) => Router w t s ((route :: Type) ': routes) pr where
143143
route _ _s parsedRoute page400 getDomReqUpdEv request req =
144144
(<>)
145145
(route (Proxy :: Proxy '(route, t)) _s parsedRoute page400 getDomReqUpdEv request req)
@@ -148,20 +148,20 @@ instance
148148
instance (Monad w, Reflex t) => Router w t s '[] pr where
149149
route _ _ _ _ _ _ _ = NotMatched
150150

151-
instance (Monad w, Router w t s rest '(m, pp :++ '[Namespace ns])) => Router w t s ((ns :: *) :// (rest :: *)) '(m, pp) where
151+
instance (Monad w, Router w t s rest '(m, pp :++ '[Namespace ns])) => Router w t s ((ns :: Type) :// (rest :: Type)) '(m, pp) where
152152
route _ _s parsedRoute page400 getDomReqUpdEv request req =
153153
route (Proxy :: Proxy '(rest, t)) _s (snocParsedRoute parsedRoute $ NSPiece (Proxy :: Proxy ns)) page400 getDomReqUpdEv request req
154154

155155
instance (Monad w, Router w t s (MarkDyn rest) '(m, (pp :++ '[DynamicPiece piece])), DecodeParam piece, Reflex t)
156-
=> Router w t s ((piece :: *) :/ (rest :: *)) '(m, pp) where
156+
=> Router w t s ((piece :: Type) :/ (rest :: Type)) '(m, pp) where
157157
route _ _s parsedRoute page400 getDomReqUpdEv reqDyn req = case pathInfo req of
158158
(lpth : rpths) -> case (decodeParam (encodeUtf8 lpth) :: Maybe piece) of
159159
Just dynPiece -> route (Proxy :: Proxy '((MarkDyn rest), t)) _s (snocParsedRoute parsedRoute $ DPiece dynPiece) page400 getDomReqUpdEv reqDyn (req {pathInfo = rpths})
160160
Nothing -> NotMatched
161161
_ -> NotMatched
162162

163163
instance (Reflex t, Monad w, Router w t s (MarkDyn rest) '(m, (pp :++ '[StaticPiece piece])), KnownSymbol piece)
164-
=> Router w t s ((piece :: Symbol) :/ (rest :: *)) '(m, pp) where
164+
=> Router w t s ((piece :: Symbol) :/ (rest :: Type)) '(m, pp) where
165165
route _ _s parsedRoute page400 getDomReqUpdEv reqDyn req = case pathInfo req of
166166
(lpth : rpths) | lpieceTxt == lpth -> route (Proxy :: Proxy '((MarkDyn rest), t)) _s (snocParsedRoute parsedRoute $ SPiece (Proxy :: Proxy piece)) page400 getDomReqUpdEv reqDyn (req {pathInfo = rpths})
167167
_ -> NotMatched
@@ -239,7 +239,7 @@ instance ( KnownSymbol rpiece
239239
, CookieIn m route ~ ()
240240
, HeaderIn m route ~ ()
241241
, RequestBody m route ~ '[]
242-
) => Router w t s ((lpiece :: *) :/ (rpiece :: Symbol)) '(m, pp) where
242+
) => Router w t s ((lpiece :: Type) :/ (rpiece :: Symbol)) '(m, pp) where
243243
route _ serv parsedRoute page400 getDomReqUpdEv reqDyn req = case pathInfo req of
244244
(lpth : rpth : [])
245245
| rpieceTxt == rpth -> case (decodeParam (encodeUtf8 lpth) :: Maybe lpiece) of
@@ -314,7 +314,7 @@ instance ( PathParam m (ns :// piece) ~ ()
314314
, CookieIn m route ~ ()
315315
, HeaderIn m route ~ ()
316316
, RequestBody m route ~ '[]
317-
) => Router w t s ((ns :: *) :// (piece :: Symbol)) '(m, pp) where
317+
) => Router w t s ((ns :: Type) :// (piece :: Symbol)) '(m, pp) where
318318
route _ serv _ page400 getDomReqUpdEv reqDyn req = case pathInfo req of
319319
(pth : []) | symTxt (Proxy :: Proxy piece) == pth -> Matched (mkUIRequestRep (undefined :: UIRequest m route), getResponse)
320320
[] | T.null $ symTxt (Proxy :: Proxy piece) -> NotMatched
@@ -471,7 +471,7 @@ toUIApplication r@UIRequest { uiPathParam, uiQueryParam } page404 app = withPath
471471
go0 =
472472
map (\(k, v) -> (T.encodeUtf8 k, pure $ T.encodeUtf8 v))
473473

474-
uiApp :: forall (t :: *) server m app r meth ac mp.
474+
uiApp :: forall (t :: Type) server m app r meth ac mp.
475475
( MonadWidget t m
476476
, MkPathFormatString (app :// r)
477477
, ToParam 'PathParam (PathParam meth (app :// r))
@@ -500,15 +500,15 @@ emptyParsedRoutes :: ParsedRoute t '(CUSTOM "", '[])
500500
emptyParsedRoutes = Nil Proxy
501501

502502

503-
data PieceType :: * -> * -> * where
503+
data PieceType :: Type -> Type -> Type where
504504
SPiece :: Proxy (p :: Symbol) -> PieceType t (StaticPiece p)
505-
NSPiece :: Proxy (ns :: *) -> PieceType t (Namespace ns)
505+
NSPiece :: Proxy (ns :: Type) -> PieceType t (Namespace ns)
506506
DPiece :: !val -> PieceType t (DynamicPiece val)
507507

508-
data ParsedRoute :: * -> (*, [*]) -> * where
508+
data ParsedRoute :: Type -> (Type, [Type]) -> Type where
509509
Nil :: Proxy method -> ParsedRoute t '(method, '[])
510510
ConsStaticPiece :: Proxy (p :: Symbol) -> ParsedRoute t '(method, ps) -> ParsedRoute t '(method, ((StaticPiece p) ': ps))
511-
ConsNSPiece :: Proxy (ns :: *) -> ParsedRoute t '(method, ps) -> ParsedRoute t '(method, ((Namespace ns) ': ps))
511+
ConsNSPiece :: Proxy (ns :: Type) -> ParsedRoute t '(method, ps) -> ParsedRoute t '(method, ((Namespace ns) ': ps))
512512
ConsDynamicPiece :: !v -> ParsedRoute t '(method, ps) -> ParsedRoute t '(method, ((DynamicPiece v) ': ps))
513513

514514
data RouteResult a =
@@ -520,10 +520,10 @@ instance Semigroup (RouteResult a) where
520520
NotMatched <> m = m
521521
Matched a <> _ = Matched a
522522

523-
type family MarkDyn (pp :: *) :: * where
523+
type family MarkDyn (pp :: Type) :: Type where
524524
MarkDyn (p1 :/ t) = (p1 :/ t)
525525
MarkDyn (p :// t) = (p :// t)
526-
MarkDyn (t :: *) = DynamicPiece t
526+
MarkDyn (t :: Type) = DynamicPiece t
527527

528528
snocParsedRoute :: ParsedRoute t '(method, ps) -> PieceType t pt -> ParsedRoute t '(method, ps :++ '[pt])
529529
snocParsedRoute nil@Nil{} (SPiece sym) = sym `ConsStaticPiece` nil
@@ -569,17 +569,17 @@ getPathParamCtor proutes domreq = fromParsedRoute' (parseDynPiece (pathInfo domr
569569
parseDynPiece pths (ConsNSPiece _ ps) = parseDynPiece pths ps
570570
parseDynPiece (p : pths) (ConsDynamicPiece _v ps) = unsafeDecodePar _v p :* parseDynPiece pths ps
571571

572-
type family AllDecodeParam (dpcs :: [*]) :: Constraint where
572+
type family AllDecodeParam (dpcs :: [Type]) :: Constraint where
573573
AllDecodeParam '[] = ()
574574
AllDecodeParam (t ': ts) = (DecodeParam t, AllDecodeParam ts)
575575

576-
data HList :: * -> [*] -> * where
576+
data HList :: Type -> [Type] -> Type where
577577
HNil :: HList t '[]
578578
(:*) :: !a -> HList t as -> HList t (a ': as)
579579
infixr 5 :*
580580

581581
-- Compact server
582-
data CompactUIServer (api :: *) (server :: *) = CompactUIServer server
582+
data CompactUIServer (api :: Type) (server :: Type) = CompactUIServer server
583583

584584
instance (WebApi api) => WebUIServer (CompactUIServer api s) where
585585
type UIInterface (CompactUIServer api s) = api
@@ -597,7 +597,7 @@ instance ( ApiContract api m r
597597
hdl :: handler
598598
hdl = getField @(GetOpIdName api (OperationId m r)) server
599599

600-
class UnifyHandler (isEq :: Bool) (server :: *) (fn :: Symbol) handlerAct handlerExp where
600+
class UnifyHandler (isEq :: Bool) (server :: Type) (fn :: Symbol) handlerAct handlerExp where
601601
unifyHandler :: handlerAct -> handlerExp
602602

603603
instance (handlerAct ~ handlerExp) => UnifyHandler 'True s fn handlerAct handlerExp where

webapi-test/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Revision history for webapi-test
2+
3+
## 0.1.0.0 -- YYYY-mm-dd
4+
5+
* First version. Released on an unsuspecting world.

webapi-test/LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Copyright (c) 2025, Magesh B
2+
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above
11+
copyright notice, this list of conditions and the following
12+
disclaimer in the documentation and/or other materials provided
13+
with the distribution.
14+
15+
* Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived
17+
from this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
module Test.WebApi.DynamicLogic
2+
( propDL
3+
, prop_api
4+
-- , runWebApiTest
5+
-- , apiAction
6+
, apiForAllVar
7+
, getCtxAtTypeDL
8+
, arbitraryVal
9+
, shrinkVal
10+
, module Test.WebApi.StateModel
11+
, Reifies
12+
, reify
13+
) where
14+
15+
import Test.WebApi.StateModel
16+
import Test.WebApi
17+
import Test.QuickCheck.StateModel
18+
import Test.QuickCheck.DynamicLogic
19+
-- import Data.Kind
20+
import Data.Typeable
21+
import Test.QuickCheck
22+
import Test.QuickCheck.Monadic
23+
import Test.QuickCheck.Monadic qualified as QC
24+
import Data.Reflection
25+
import Data.IORef
26+
import qualified Record
27+
-- import Control.Monad.IO.Class
28+
import Control.Monad.Reader
29+
30+
propDL :: forall c xstate apps e s.
31+
( DynLogicModel xstate
32+
, RunModel xstate IO
33+
, XActionError e ~ Error xstate IO
34+
, Typeable e
35+
, Show e
36+
, Reifies s (WebApiGlobalStateModel c xstate apps)
37+
) => Proxy s -> (forall a. WebApiSessions apps a -> IO a) -> DL (ApiState s c xstate apps) () -> Property
38+
propDL _ webapiRunner d = forAllDL d (prop_api undefined webapiRunner)
39+
40+
prop_api :: forall c xstate apps e s.
41+
( DynLogicModel xstate
42+
, RunModel xstate IO
43+
, XActionError e ~ Error xstate IO
44+
, Typeable e
45+
, Show e
46+
, Reifies s (WebApiGlobalStateModel c xstate apps)
47+
) => IORef (Maybe (ApiState s c xstate apps))
48+
-> (forall a. WebApiSessions apps a -> IO a)
49+
-> Actions (ApiState s c xstate apps)
50+
-> Property
51+
prop_api _newStRef webapiRunner s =
52+
-- let
53+
-- runner =
54+
monadic (ioProperty . webapiRunner . flip runReaderT initWebApiSessionsCxt) $ do
55+
monitor $ counterexample "\nExecution\n"
56+
(_anonSt, _env) <- runActions s
57+
-- let
58+
-- newApiState = resolveNamedEntities env $ underlyingState anonSt
59+
-- liftIO $ writeIORef newStRef (Just newApiState)
60+
QC.assert True
61+
62+
-- runWebApiTest :: forall r apps. WebApiGlobalStateModel apps -> (forall (s :: Type). Reifies s (WebApiGlobalStateModel apps) => Proxy s -> r) -> r
63+
-- runWebApiTest gstate runner = reify gstate (\ps -> runner ps)
64+
65+
-- apiAction ::
66+
-- ( Typeable a
67+
-- , Eq (Action (ApiState s apps) a)
68+
-- , Show (Action (ApiState s apps) a)
69+
-- , ContextSwitch c
70+
-- ) => ApiActionM c apps (DL (ApiState s apps)) (ApiAction apps a)
71+
-- -> ApiActionM c apps (DL (ApiState s apps)) (Val a)
72+
-- apiAction actM = do
73+
-- ApiAction act <- actM
74+
-- liftApiDL $ fmap (Var id) $ action act
75+
76+
-- getModelStateDL >>= (\st -> fmap (Var id) . action $ act st)
77+
78+
-- apiAction' :: (Typeable a, Eq (Action s a), Show (Action s a)) => Action s a -> DL s (Val a)
79+
-- apiAction' = fmap (Var id) . action
80+
81+
apiForAllVar :: forall a s. Typeable a => DL s (Val a)
82+
apiForAllVar = fmap (Var id) forAllVar
83+
84+
getCtxAtTypeDL :: forall a s. Typeable a => DL s [Val a]
85+
getCtxAtTypeDL = (fmap (Var id) . ctxAtType @a) <$> getVarContextDL
86+
87+
arbitraryVal :: Typeable a => VarContext -> Gen (Val a)
88+
arbitraryVal = fmap (Var id) . arbitraryVar
89+
90+
shrinkVal :: forall a. Typeable a => VarContext -> Val a -> [Val a]
91+
shrinkVal vctx = \case
92+
v@Const {} -> [v]
93+
Var f v -> fmap (Var f) $ shrinkVar vctx v
94+
v@Opt {} -> [v]
95+
HKVal f hk -> fmap (HKVal f) $ Record.hoistWithKeyHKA (shrinkVal vctx) hk
96+
Pair f (v1, v2) -> fmap (Pair f) $ (,) <$> (shrinkVal vctx v1) <*> (shrinkVal vctx v2)

0 commit comments

Comments
 (0)