-
Notifications
You must be signed in to change notification settings - Fork 10
Description
From @RocketPuppy on September 6, 2016 0:53
While working on generating a mock server of my API (which is really cool now that I have it working), I ran into several issues regarding AuthProtect.
The first issue is simply that there isn't an instance for HasMock covering the AuthProtect combinator. Now that I've "implemented" one I think I'm starting to see why. The second issue is that authentication using AuthProtect is still done even in the mock servers. I have something working now but I'm not confident in it. I'll try and walk through my steps below.
Suppose an API like:
type API = AuthProtect "cookie-auth" AuthCookie :> Get '[JSON] SecretSauceIn order to mock I did the following:
api = Proxy :: Proxy API
type AppContext = '[ AuthHandler Request AuthCookie ]
context :: Context AppContext
context = (myAuthHandler :: AuthHandler Request AuthCookie) :. EmptyContext
mockServer = serveWithContext api context (mock api (Proxy :: AppContext))context is used in the canonical implementation of the API to provide the authentication handler. The first problem I ran into was the lack of a HasMock instance. I came up with the following:
instance ( HasMock rest context
, HasServer rest context
, HasContextEntry context (AuthHandler Request (AuthServerData (AuthProtect sym)))
) =>
HasMock (AuthProtect (sym :: Symbol) :> rest) context where
mock _ context = \_ -> mock (Proxy :: Proxy rest) contextWhich I'm not very happy with because it requires UndecidableInstances. The second problem I ran into, after I had that working, was that authentication still happens on the mock server. I'm on the fence as to whether this is actually a problem, but it was undesirable in my circumstances. I came up with the following solution:
mockAuthHandler :: (Arbitrary a) => AuthHandler Request a
mockAuthHandler = mkAuthHandler $ \ _ -> liftIO $ generate arbitrary
mockContext :: Context AppContext
mockContext = (mockAuthHandler :: AuthHandler Request AuthCookie) :. Context
-- and use mockContext in the mock server
mockServer = serveWithContext api mockContext (mock api (Proxy :: AppContext))mockAuthHandler is always successful at authenticating a user.
Altogether this solution works, in that I can run a mock server and get arbitrary values from the endpoints. But I wouldn't say that servant-mock plays well with AuthProtect.
I'd be interested in better solutions than the one I hacked up here.
Copied from original issue: haskell-servant/servant#596