GithubHelp home page GithubHelp logo

haskell-servant / servant-mock Goto Github PK

View Code? Open in Web Editor NEW
19.0 19.0 9.0 87 KB

Derive a mock server for free from your servant API types

License: BSD 3-Clause "New" or "Revised" License

Haskell 98.42% C 1.58%

servant-mock's People

Contributors

alpmestan avatar arianvp avatar codedmart avatar fisx avatar fizruk avatar int-index avatar jkarni avatar jml avatar lcycon avatar luigy avatar phadej avatar soenkehahn avatar sol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

servant-mock's Issues

Servant-mock and AuthProtect

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] SecretSauce

In 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) 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:

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

Test suite build failure with servant 0.9

As seen on the Stackage build server:

Preprocessing test suite 'spec' for servant-mock-0.8.1...
[1 of 2] Compiling Servant.MockSpec ( test/Servant/MockSpec.hs, dist/build/spec/spec-tmp/Servant/MockSpec.o )

test/Servant/MockSpec.hs:69:13: error:
    • No instance for (ToHttpApiData TestHeader)
        arising from a use of ‘toApp’
    • In the first argument of ‘with’, namely ‘(toApp withHeader)’
      In the expression: with (toApp withHeader)
      In a stmt of a 'do' block:
        with (toApp withHeader)
        $ do { it "serves arbitrary response bodies"
               $ do { get "/"
                      `shouldRespondWith`
                        200 {matchHeaders = return $ MatchHeader $ ...} } }

Fails to Build with GHC 9.2.5

Hi @alpmestan

I'm trying to build this with a newer GHC ( 9.2.5 ) with stackage with resolver == lts-20.4 and it seems to fail.

The following errors show up

servant-mock/src/Servant/Mock.hs:121:10: error:
    • Could not deduce (base-4.16.4.0:Data.Typeable.Internal.Typeable
                          a)
        arising from the superclasses of an instance declaration
      from the context: (KnownSymbol s, FromHttpApiData a,
                         HasMock rest context, SBoolI (FoldLenient mods))
        bound by the instance declaration at src/Servant/Mock.hs:121:10-139
    • In the instance declaration for
        ‘HasMock (Capture' mods s a :> rest) context’
    |
121 | instance (KnownSymbol s, FromHttpApiData a, HasMock rest context, SBoolI (FoldLenient mods)) => HasMock (Capture' mods s a :> rest) context where
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

And

servant-mock/src/Servant/Mock.hs:124:10: error:
    • Could not deduce (base-4.16.4.0:Data.Typeable.Internal.Typeable
                          a)
        arising from the superclasses of an instance declaration
      from the context: (KnownSymbol s, FromHttpApiData a,
                         HasMock rest context)
        bound by the instance declaration at src/Servant/Mock.hs:124:10-109
    • In the instance declaration for
        ‘HasMock (CaptureAll s a :> rest) context’
    |
124 | instance (KnownSymbol s, FromHttpApiData a, HasMock rest context) => HasMock (CaptureAll s a :> rest) context where
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Example in Haddock docs for Servant.Mock no longer builds without error

The Haddock documentation for Servant.Mock gives example code similar to what's found in example/main.hs, but with the most recent version of the package (0.8.7), the code in the Haddock documentation no longer compiles.

The module-level haddock documentation suggests the following should compile:

--  we need imports and User definition and instance -- we'll use the one from example/main.hs

import           Data.Aeson
import           GHC.Generics
import           Network.Wai.Handler.Warp
import           Servant
import           Servant.Mock
import           Test.QuickCheck.Arbitrary

newtype User = User { username :: String }
  deriving (Eq, Show, Arbitrary, Generic)

instance ToJSON User

-- paste in the example from the Haddock documentation:

type API = "user" :> Get '[JSON] User

myAPI :: Proxy API
myAPI = Proxy

main :: IO ()
main = Network.Wai.Handler.Warp.run 8080 $
  serve myAPI (mock myAPI Proxy)

However, in the arguments to serve, it seems a reasonably recent GHC (8.6.5) can't deduce the type of the second Proxy (whereas it could for servant-mock 0.8.5).

I used the Docker image for GHC 8.6.5 (running docker -D run --rm -it haskell:8.6.5 bash), and pasted the above code into example/main.hs, and within the container ran:

$ stack unpack servant-mock-0.8.7
$ cd servant-mock-0.8.7
$ cabal v2-update
$ cabal v2-build --dependencies-only all
$ cabal v2-build all

I get the following compile error:

[1 of 1] Compiling Main             ( example/main.hs, /root/servant-mock-0.8.7/dist-newstyle/build/x86_64-linux/ghc-8.6.5/servant-mock-0.8.7/x/mock-app/build/mock-app/mock-app-tmp/Main.o )

example/main.hs:33:16: error:
    * Ambiguous type variable `context0' arising from a use of `mock'
      prevents the constraint `(HasContextEntry
                                  (context0 .++ DefaultErrorFormatters)
                                  ErrorFormatters)' from being solved.
      Probable fix: use a type annotation to specify what `context0' should be.
      These potential instances exist:
        two instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    * In the second argument of `serve', namely `(mock myAPI Proxy)'
      In the second argument of `($)', namely
        `serve myAPI (mock myAPI Proxy)'
      In the expression: run 8080 $ serve myAPI (mock myAPI Proxy)
   |
33 |   serve myAPI (mock myAPI Proxy)

I assume this is due to some change in servant-mock and the other servant packages, since the example seems to build with no issues using servant-mock 0.8.5 and the same version of GHC.

The example/main.hs code shows the fix - add a type declaration to the Proxy, thus: (Proxy :: Proxy '[])). But it seems worthwhile updating the Haddock documentation to reflect this.

(I'm not using contexts in my own project, so I don't know if that is an unduly restrictive signature and something looser could be used.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.