haskell-servant / haskell-servant/servant-mock
Servant-mock and AuthProtect
- Dominant language
- Haskell
- Stars
- 19
- Forks
- 10
- PR merge metrics
- No merged PRs in 30d
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:
``` haskell
type API = AuthProtect "cookie-auth" AuthCookie :> Get '[JSON] SecretSauce
```
In order to mock I did the following:
``` haskell
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:
``` haskell
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) context
```
Which 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:
``` haskell
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_
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by examining the HasMock handling for AuthProtect and the mock server setup shown in the issue, including serveWithContext and the AuthHandler context. Determine whether mocks should bypass authentication or use a generated successful handler, then define the supported behavior and verify it with an AuthProtect API like the example.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- haskell
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100