servant-checked-exceptions 0.1.0.0 → 0.1.0.1
raw patch · 10 files changed
+214/−1 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- servant-checked-exceptions.cabal +1/−1
- src/Servant/Checked/Exceptions/Internal.hs +12/−0
- src/Servant/Checked/Exceptions/Internal/Envelope.hs +79/−0
- src/Servant/Checked/Exceptions/Internal/Product.hs +11/−0
- src/Servant/Checked/Exceptions/Internal/Servant.hs +12/−0
- src/Servant/Checked/Exceptions/Internal/Servant/API.hs +13/−0
- src/Servant/Checked/Exceptions/Internal/Servant/Client.hs +13/−0
- src/Servant/Checked/Exceptions/Internal/Servant/Docs.hs +18/−0
- src/Servant/Checked/Exceptions/Internal/Servant/Server.hs +13/−0
- src/Servant/Checked/Exceptions/Internal/Union.hs +42/−0
servant-checked-exceptions.cabal view
@@ -1,5 +1,5 @@ name: servant-checked-exceptions-version: 0.1.0.0+version: 0.1.0.1 synopsis: Checked exceptions for Servant APIs. description: Please see <https://github.com/cdepillabout/servant-checked-exceptions#readme README.md>. homepage: https://github.com/cdepillabout/servant-checked-exceptions
src/Servant/Checked/Exceptions/Internal.hs view
@@ -1,3 +1,15 @@+{- |+Module : Servant.Checked.Exceptions.Internal++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++Export all of the internal functions.+-} module Servant.Checked.Exceptions.Internal ( module Servant.Checked.Exceptions.Internal.Envelope
src/Servant/Checked/Exceptions/Internal/Envelope.hs view
@@ -300,6 +300,85 @@ => Envelope es a -> Maybe e errEnvelopeMatch = preview _ErrEnvelopeErr +-- | An alternate case anaylsis for an 'Envelope'. This method uses a tuple+-- containing handlers for each potential value of the 'Envelope'. This is+-- somewhat similar to the 'Control.Exception.catches' function.+--+-- Here is an example of handling an 'SuccEnvelope' with two possible error values.+-- Notice that a normal tuple is used:+--+-- >>> let env = toSuccEnvelope 2.0 :: Envelope '[Int, String] Double+-- >>> let intHandler = (\int -> show int) :: Int -> String+-- >>> let strHandler = (\str -> str) :: String -> String+-- >>> let succHandler = (\dbl -> "got a double") :: Double -> String+-- >>> catchesEnvelope (intHandler, strHandler) succHandler env :: String+-- "got a double"+--+-- Here is an example of handling an 'ErrEnvelope' with two possible error values.+-- Notice that a normal tuple is used to hold the handlers:+--+-- >>> let env = toErrEnvelope (3 :: Int) :: Envelope '[Int, String] Double+-- >>> let intHandler = (\int -> show int) :: Int -> String+-- >>> let strHandler = (\str -> str) :: String -> String+-- >>> let succHandler = (\dbl -> "got a double") :: Double -> String+-- >>> catchesEnvelope (intHandler, strHandler) succHandler env :: String+-- "3"+--+-- Given an 'Envelope' like @'Envelope' \'['Int', 'String'] Double@, the type of+-- 'catchesEnvelope' becomes the following:+--+-- @+-- 'catchesEnvelope'+-- :: ('Int' -> x, 'String' -> x)+-- -> ('Double' -> x)+-- -> 'Envelope' \'['Int', 'String'] Double+-- -> x+-- @+--+-- Here is an example of handling an 'ErrEnvelope' with three possible values.+-- Notice how a 3-tuple is used to hold the handlers:+--+-- >>> let env = toErrEnvelope ("hi" :: String) :: Envelope '[Int, String, Char] Double+-- >>> let intHandler = (\int -> show int) :: Int -> String+-- >>> let strHandler = (\str -> str) :: String -> String+-- >>> let chrHandler = (\chr -> [chr]) :: Char -> String+-- >>> let succHandler = (\dbl -> "got a double") :: Double -> String+-- >>> catchesEnvelope (intHandler, strHandler, chrHandler) succHandler env :: String+-- "hi"+--+-- Given an 'Envelope' like @'Envelope' \'['Int', 'String', 'Char'] Double@,+-- the type of 'catchesEnvelope' becomes the following:+--+-- @+-- 'catchesEnvelope'+-- :: ('Int' -> x, 'String' -> x, 'Char' -> x)+-- -> ('Double' -> x)+-- -> 'Envelope' \'['Int', 'String', 'Char'] Double+-- -> x+-- @+--+-- Here is an example of handling an 'ErrEnvelope' with only one possible error value.+-- Notice that a normal hanlders is used (not a tuple):+--+-- >>> let env = toErrEnvelope (3 :: Int) :: Envelope '[Int] Double+-- >>> let intHandler = (\int -> show int) :: Int -> String+-- >>> let succHandler = (\dbl -> "got a double") :: Double -> String+-- >>> catchesEnvelope intHandler succHandler env :: String+-- "3"+--+-- Given an 'Envelope' like @'Envelope' \'['Int'] Double@, the type of+-- 'catchesEnvelope' becomes the following:+--+-- @+-- 'catchesEnvelope'+-- :: ('Int' -> x)+-- -> ('Double' -> x)+-- -> 'Envelope' \'['Int'] Double+-- -> x+-- @+--+-- When working with an 'Envelope' with a large number of possible error types,+-- it can be easier to use 'catchesEnvelope' than 'envelope'. catchesEnvelope :: forall tuple es a x. ToOpenProduct tuple (ReturnX x es)
src/Servant/Checked/Exceptions/Internal/Product.hs view
@@ -49,20 +49,25 @@ -- | This type class provides a way to turn a tuple into a 'Product'. class ToProduct (tuple :: *) (f :: u -> *) (as :: [u]) | f as -> tuple where+ -- | Convert a tuple into a 'Product'. See 'tupleToProduct' for examples. toProduct :: tuple -> Product f as +-- | Convert a single value into a 'Product'. instance forall (f :: u -> *) (a :: u). ToProduct (f a) f '[a] where toProduct :: f a -> Product f '[a] toProduct fa = Cons fa Nil +-- | Convert a tuple into a 'Product'. instance forall (f :: u -> *) (a :: u) (b :: u). ToProduct (f a, f b) f '[a, b] where toProduct :: (f a, f b) -> Product f '[a, b] toProduct (fa, fb) = Cons fa $ Cons fb Nil +-- | Convert a 3-tuple into a 'Product'. instance forall (f :: u -> *) (a :: u) (b :: u) (c :: u). ToProduct (f a, f b, f c) f '[a, b, c] where toProduct :: (f a, f b, f c) -> Product f '[a, b, c] toProduct (fa, fb, fc) = Cons fa $ Cons fb $ Cons fc Nil +-- | Convert a 4-tuple into a 'Product'. instance forall (f :: u -> *) (a :: u) (b :: u) (c :: u) (d :: u). ToProduct (f a, f b, f c, f d) f '[a, b, c, d] where toProduct :: (f a, f b, f c, f d) -> Product f '[a, b, c, d] toProduct (fa, fb, fc, fd) = Cons fa $ Cons fb $ Cons fc $ Cons fd Nil@@ -86,21 +91,25 @@ class ToOpenProduct (tuple :: *) (as :: [*]) | as -> tuple where toOpenProduct :: tuple -> OpenProduct as +-- | Convert a single value into an 'OpenProduct'. instance forall (a :: *). ToOpenProduct a '[a] where toOpenProduct :: a -> OpenProduct '[a] toOpenProduct a = Cons (Identity a) Nil +-- | Convert a tuple into an 'OpenProduct'. instance forall (a :: *) (b :: *). ToOpenProduct (a, b) '[a, b] where toOpenProduct :: (a, b) -> OpenProduct '[a, b] toOpenProduct (a, b) = Cons (Identity a) $ Cons (Identity b) Nil +-- | Convert a 3-tuple into an 'OpenProduct'. instance forall (a :: *) (b :: *) (c :: *). ToOpenProduct (a, b, c) '[a, b, c] where toOpenProduct :: (a, b, c) -> OpenProduct '[a, b, c] toOpenProduct (a, b, c) = Cons (Identity a) $ Cons (Identity b) $ Cons (Identity c) Nil +-- | Convert a 4-tuple into an 'OpenProduct'. instance forall (a :: *) (b :: *) (c :: *) (d :: *). ToOpenProduct (a, b, c, d) '[a, b, c, d] where@@ -129,10 +138,12 @@ -- Instances -- --------------- +-- | Show 'Nil' values. instance Show (Product f '[]) where show :: Product f '[] -> String show Nil = "Nil" +-- | Show 'Cons' values. instance (Show (f a), Show (Product f as)) => Show (Product f (a ': as)) where showsPrec :: Int -> (Product f (a ': as)) -> String -> String showsPrec n (Cons fa prod) = showParen (n > 10) $
src/Servant/Checked/Exceptions/Internal/Servant.hs view
@@ -1,3 +1,15 @@+{- |+Module : Servant.Checked.Exceptions.Internal.Servant++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++Export all of instances for the Client, Docs, and Server.+-} module Servant.Checked.Exceptions.Internal.Servant ( module Servant.Checked.Exceptions.Internal.Servant.API
src/Servant/Checked/Exceptions/Internal/Servant/API.hs view
@@ -1,6 +1,19 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} +{- |+Module : Servant.Checked.Exceptions.Internal.Servant.API++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module defines the 'Throws' and 'Throwing' types.+-}+ module Servant.Checked.Exceptions.Internal.Servant.API where -- | 'Throws' is used in Servant API definitions and signifies that an API will
src/Servant/Checked/Exceptions/Internal/Servant/Client.hs view
@@ -11,6 +11,19 @@ {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} +{- |+Module : Servant.Checked.Exceptions.Internal.Servant.Client++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module only exports 'HasClient' instances for 'Throws' and 'Throwing'.+-}+ module Servant.Checked.Exceptions.Internal.Servant.Client where import Data.Proxy (Proxy(Proxy))
src/Servant/Checked/Exceptions/Internal/Servant/Docs.hs view
@@ -13,6 +13,19 @@ {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} +{- |+Module : Servant.Checked.Exceptions.Internal.Servant.Docs++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module exports 'HasDocs' instances for 'Throws' and 'Throwing'.+-}+ module Servant.Checked.Exceptions.Internal.Servant.Docs where import Control.Lens ((&), (<>~))@@ -45,6 +58,9 @@ -> API docsFor Proxy = docsFor (Proxy :: Proxy (Throwing '[e] :> api)) +-- | When @'Throwing' es@ comes before a 'Verb', generate the documentation for+-- the same 'Verb', but returning an @'Envelope' es@. Also add documentation+-- for the potential @es@. instance ( CreateRespBodiesFor es ctypes , HasDocs (Verb method status ctypes (Envelope es a))@@ -73,6 +89,7 @@ -> Proxy ctypes -> [(Text, MediaType, ByteString)] +-- | An empty list of types has no samples. instance CreateRespBodiesFor '[] ctypes where createRespBodiesFor :: Proxy '[]@@ -80,6 +97,7 @@ -> [(Text, MediaType, ByteString)] createRespBodiesFor Proxy Proxy = [] +-- | Create a response body for each of the error types. instance ( AllMimeRender ctypes (Envelope '[e] ()) , CreateRespBodiesFor es ctypes
src/Servant/Checked/Exceptions/Internal/Servant/Server.hs view
@@ -11,6 +11,19 @@ {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} +{- |+Module : Servant.Checked.Exceptions.Internal.Servant.Server++Copyright : Dennis Gosnell 2017+License : BSD3++Maintainer : Dennis Gosnell (cdep.illabout@gmail.com)+Stability : experimental+Portability : unknown++This module exports 'HasServer' instances for 'Throws' and 'Throwing'.+-}+ module Servant.Checked.Exceptions.Internal.Servant.Server where import Data.Proxy (Proxy(Proxy))
src/Servant/Checked/Exceptions/Internal/Union.hs view
@@ -379,6 +379,48 @@ => OpenUnion as -> Maybe a openUnionMatch = preview openUnionPrism +-- | An alternate case anaylsis for an 'OpenUnion'. This method uses a tuple+-- containing handlers for each potential value of the 'OpenUnion'. This is+-- somewhat similar to the 'Control.Exception.catches' function.+--+-- Here is an example of handling an 'OpenUnion' with two possible values.+-- Notice that a normal tuple is used:+--+-- >>> let u = openUnionLift (3 :: Int) :: OpenUnion '[Int, String]+-- >>> let intHandler = (\int -> show int) :: Int -> String+-- >>> let strHandler = (\str -> str) :: String -> String+-- >>> catchesOpenUnion (intHandler, strHandler) u :: String+-- "3"+--+-- Given an 'OpenUnion' like @'OpenUnion' \'['Int', 'String']@, the type of+-- 'catchesOpenUnion' becomes the following:+--+-- @+-- 'catchesOpenUnion'+-- :: ('Int' -> x, 'String' -> x)+-- -> 'OpenUnion' \'['Int', 'String']+-- -> x+-- @+--+-- Here is an example of handling an 'OpenUnion' with three possible values:+--+-- >>> let u = openUnionLift ("hello" :: String) :: OpenUnion '[Int, String, Double]+-- >>> let intHandler = (\int -> show int) :: Int -> String+-- >>> let strHandler = (\str -> str) :: String -> String+-- >>> let dblHandler = (\dbl -> "got a double") :: Double -> String+-- >>> catchesOpenUnion (intHandler, strHandler, dblHandler) u :: String+-- "hello"+--+-- Here is an example of handling an 'OpenUnion' with only one possible value.+-- Notice how a tuple is not used, just a single value:+--+-- >>> let u = openUnionLift (2.2 :: Double) :: OpenUnion '[Double]+-- >>> let dblHandler = (\dbl -> "got a double") :: Double -> String+-- >>> catchesOpenUnion dblHandler u :: String+-- "got a double"+--+-- When working with large 'OpenUnion's, it can be easier to use+-- 'catchesOpenUnion' than 'openUnion'. catchesOpenUnion :: ToOpenProduct tuple (ReturnX x as) => tuple -> OpenUnion as -> x