diff --git a/servant-mock/servant-mock.cabal b/servant-mock/servant-mock.cabal index e7d70b15..a6e8119d 100644 --- a/servant-mock/servant-mock.cabal +++ b/servant-mock/servant-mock.cabal @@ -1,10 +1,10 @@ --- Initial servant-mock.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/ - name: servant-mock version: 0.4 synopsis: Derive a mock server for free from your servant API types -description: Derive a mock server for free from your servant API types +description: + Derive a mock server for free from your servant API types + . + See the @Servant.Mock@ module for the documentation and an example. homepage: http://github.com/haskell-servant/servant license: BSD3 license-file: LICENSE @@ -13,7 +13,6 @@ maintainer: alpmestan@gmail.com copyright: 2015 Alp Mestanogullari category: Web build-type: Simple --- extra-source-files: cabal-version: >=1.10 flag example diff --git a/servant-mock/src/Servant/Mock.hs b/servant-mock/src/Servant/Mock.hs index e50b4926..9382d40f 100644 --- a/servant-mock/src/Servant/Mock.hs +++ b/servant-mock/src/Servant/Mock.hs @@ -5,6 +5,49 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} +-- | +-- Module : Servant.Mock +-- Copyright : 2015 Alp Mestanogullari +-- License : BSD3 +-- +-- Maintainer : Alp Mestanogullari +-- Stability : experimental +-- Portability : portable +-- +-- Automatically derive a mock webserver that implements some API type, +-- just from the said API type's definition. +-- +-- Using this module couldn't be simpler. Given some API type, like: +-- +-- > type API = "user" :> Get '[JSON] User +-- +-- that describes your web application, all you have to do is define +-- a 'Proxy' to it: +-- +-- > myAPI :: Proxy API +-- > myAPI = Proxy +-- +-- and call 'mock', which has the following type: +-- +-- @ +-- 'mock' :: 'HasMock' api => 'Proxy' api -> 'Server' api +-- @ +-- +-- What this says is, given some API type @api@ that it knows it can +-- "mock", 'mock' hands you an implementation of the API type. It does so +-- by having each request handler generate a random value of the +-- appropriate type (@User@ in our case). All you need for this to work is +-- to provide 'Arbitrary' instances for the data types returned as response +-- bodies, hence appearing next to 'Delete', 'Get', 'Patch', 'Post' and 'Put'. +-- +-- To put this all to work and run the mock server, just call 'serve' on the +-- result of 'mock' to get an 'Application' that you can then run with warp. +-- +-- @ +-- main :: IO () +-- main = Network.Wai.Handler.Warp.run 8080 $ +-- 'serve' myAPI ('mock' myAPI) +-- @ module Servant.Mock ( HasMock(..) ) where #if !MIN_VERSION_base(4,8,0) @@ -21,7 +64,40 @@ import Servant.API.ContentTypes import Test.QuickCheck.Arbitrary (Arbitrary(..), vector) import Test.QuickCheck.Gen (Gen, generate) +-- | 'HasMock' defines an interpretation of API types +-- than turns them into random-response-generating +-- request handlers, hence providing an instance for +-- all the combinators of the core /servant/ library. class HasServer api => HasMock api where + -- | Calling this method creates request handlers of + -- the right type to implement the API described by + -- @api@ that just generate random response values of + -- the right type. E.g: + -- + -- @ + -- type API = "user" :> Get '[JSON] User + -- :<|> "book" :> Get '[JSON] Book + -- + -- api :: Proxy API + -- api = Proxy + -- + -- -- let's say we will start with the frontend, + -- -- and hence need a placeholder server + -- server :: Server API + -- server = mock api + -- @ + -- + -- What happens here is that @'Server' API@ + -- actually "means" 2 request handlers, of the following types: + -- + -- @ + -- getUser :: EitherT ServantErr IO User + -- getBook :: EitherT ServantErr IO Book + -- @ + -- + -- So under the hood, 'mock' uses the 'IO' bit to generate + -- random values of type 'User' and 'Book' every time these + -- endpoints are requested. mock :: Proxy api -> Server api instance (HasMock a, HasMock b) => HasMock (a :<|> b) where