-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A library to generate REST-style webservices on top of scotty, handling all the boilerplate for you -- -- An abstraction for Resources that can support any number of -- operations, which will be tagged at the type-level. -- -- This package however does provide standard REST-y operations -- (Servant.Prelude.Add, Servant.Prelude.Delete, -- Servant.Prelude.ListAll , Servant.Prelude.Update and -- Servant.Prelude.View) and lets you define your own. -- -- You can then actually make a service out of a -- Servant.Resource.Resource description using any backend you -- like (we currently only provide a scotty backend in the -- servant-scotty package). -- -- Head to the README for information and links to documentation. @package servant @version 0.1 -- | Everything you'll need when doing some kind of exception handling -- around your "database operations". module Servant.Error -- | A container for zero or more exception catchers. -- -- By exception catcher, we mean here a function that can convert some -- precise instance of Exception to the error type used in your -- scotty app (the e type in Servant.Resource -- Servant.Service) data ExceptionCatcher err -- | Don't catch any exception. noCatch :: ExceptionCatcher err -- | Create an ExceptionCatcher from a function. -- -- This will make the catcher aware of exceptions of type except -- so that when you'll run a catcher against an IO action using -- raiseIfExc or handledWith, if an exception of this -- type is thrown, it will be caught and converted to the error type of -- your web application using the provided function. catchAnd :: Exception except => (except -> err) -> ExceptionCatcher err -- | Combine two ExceptionCatcher. -- -- The resulting ExceptionCatcher will be able to catch exceptions -- using the catchers from both arguments. combineCatchers :: ExceptionCatcher err -> ExceptionCatcher err -> ExceptionCatcher err -- | Run an IO action by watching for all the exceptions supported -- by the ExceptionCatcher. -- -- If an exception is thrown somewhere in the action and is caught by the -- catcher, it will call the function given to catchAnd to convert -- the exception value to the error type of your scotty application. -- -- If an exception is thrown whose type isn't one for which there's a -- catcher in the ExceptionCatcher argument, you'll have to -- catch it yourself or let it be sent to the default handler. -- -- Since runService sets up a defaultHandler, you'll most -- likely want to directly use raiseIfExc which raises -- the error value you got from the exception if some exception is thrown -- or just run some scotty action if everything went smoothly. This means -- writing a handler that'll set up a response with the proper HTTP -- status and send some JSON to the client with an informative error -- message, which... isn't a bad thing :-) handledWith :: IO a -> ExceptionCatcher err -> IO (Either err a) instance Monoid (ExceptionCatcher err) -- | A Context type for holding a function that will use some -- context to execute something analoguous to a database -- operation. -- -- This is equivalent to holding something like: -- --
-- withConnection someConnection ---- -- where you have previously set up someConnection by specifying -- a connection string or something like that. This lets us support any -- kind of backend (even an in-memory Map in an IORef), and most -- interestingly, we can use just raw connections or a connection pool, -- this approach really covers a lot of situations while keeping -- everything quite simple. module Servant.Context -- | A Context is just a wrapper around a function that can execute -- IO operations given this context. data Context c -- | Create a Context from a suitable function mkContext :: (forall r. (c -> IO r) -> IO r) -> Context c -- | Use the Context to actually perform an IO operation -- requiring it. withContext :: Context c -> (c -> IO r) -> IO r -- | Defining Resources. module Servant.Resource -- | A resource that: -- --
-- withContext (context resource) $ \c -> ... ---- -- where c could be a PostgreSQL connection, for example. mkResource :: String -> Context c -> ExceptionCatcher e -> Resource c a i r e '[] -- | Add an operation to a resource by specifying the "database function" -- that'll actually perform the lookup, update, listing, search and what -- not. -- -- We statically enforce that the operation we're adding isn't already -- supported by the Resource, when built with ghc >= -- 7.8. addOperation :: Contains o ops ~ False => Operation o c a i r -> Resource c a i r e ops -> Resource c a i r e (o : ops) -- | Map an operation tag o to some combination of the other type -- parameters. -- -- For instance, if we look at Add, we know that we'll need our -- "connection type" c and a value to add, of type a. -- The result will be of type IO (r Add). If we put this all -- together, we get: -- --
-- type instance Operation Add c a i r = a -> c -> IO (r Add) ---- -- Whereas for listing all entries (ListAll), we just want some -- kind of connection c and we get back [a]. -- --
-- type instance Operation ListAll c a i r = c -> IO [a] ---- | Reversed function application. -- --
-- x & f = f x --(&) :: a -> (a -> b) -> b -- | Type level map-like function that replaces an operation's tag -- by the type of the associated "database function" -- -- For example: -- --
-- Ops [Add, List] c a i r ---- -- will result in: -- --
-- [ a -> c -> IO r -- what 'Add' is replaced by -- , c -> IO [a] -- what 'List' is replaced by -- ] ---- -- This is useful as we can exactly determine the type of the -- heterogeneous list that holds the actual "dtabase functions" that will -- perform the operations, using Ops. This among other things -- enforces a strong correspondance between the type-level list of -- operations and the (heterogeneous) list of functions held in the -- Resource we're interested in. -- -- That means we can't magically convert a Resource into one that -- supports one more operations without registering a function for it -- (which must have the right type, or your code won't compile. -- | Utility (closed) type family to detect whether a type is contained in -- a type-level list of types type Contains (elem :: *) (list :: [*]) = False instance (Show o, Show (Resource c a i r e ops)) => Show (Resource c a i r e ((':) * o ops)) instance Show (Resource c a i r e ('[] *)) -- | Some standard REST-y operations your Resources can support out -- of the box. -- -- Your type will have to implement a couple of class instances to be -- usable with a backend. For the scotty backend, this means having -- FromJSON or ToJSON instances and the appropriate -- toResponse implementations for the return types of your -- database. module Servant.Prelude -- | A dummy type representing an operation that adds an entry. data Add -- | Make a Resource support the Add operation by using your -- function. -- -- Given: -- --
-- addPerson :: PGSQL.Connection -> Person -> IO Bool ---- -- you could do: -- --
-- mkResource "persons" postgresContext noErrorHandling -- & addWith addPerson --addWith :: Contains Add ops ~ False => (a -> c -> IO (r Add)) -> Resource c a i r e ops -> Resource c a i r e (Add : ops) -- | A dummy type representing an operation that deletes an entry. data Delete -- | Make a Resource support the Delete operation by using -- your function. -- -- Given: -- --
-- deletePerson :: PGSQL.Connection -> PersonId -> IO Bool ---- -- you could do: -- --
-- mkResource "persons" postgresContext noErrorHandling -- & deleteWith addPerson --deleteWith :: Contains Delete ops ~ False => (i -> c -> IO (r Delete)) -> Resource c a i r e ops -> Resource c a i r e (Delete : ops) -- | A dummy type representing an operation that lists all entries. data ListAll -- | Make a Resource support the ListAll operation by using -- your function. -- -- Given: -- --
-- listAllPersons :: PGSQL.Connection -> IO [Person] ---- -- you could do: -- --
-- mkResource "persons" postgresContext noErrorHandling -- & listAllWith listAllPersons --listAllWith :: Contains ListAll ops ~ False => (c -> IO [a]) -> Resource c a i r e ops -> Resource c a i r e (ListAll : ops) -- | A dummy type representing an operation that updates an entry. data Update -- | Make a Resource support the Update operation by using -- your function. -- -- Given: -- --
-- updatePerson :: PGSQL.Connection -> PersonId -> Person -> IO Bool ---- -- you could do: -- --
-- mkResource "persons" postgresContext noErrorHandling -- & updateWith updatePerson --updateWith :: Contains Update ops ~ False => (i -> a -> c -> IO (r Update)) -> Resource c a i r e ops -> Resource c a i r e (Update : ops) -- | A dummy type representing an operation that looks up an entry. data View -- | Make a Resource support the View operation by using your -- function. -- -- Given: -- --
-- viewPerson :: PGSQL.Connection -> PersonId -> IO (Maybe Person) ---- -- you could do: -- --
-- mkResource "persons" postgresContext noErrorHandling -- & viewWith viewPerson --viewWith :: Contains View ops ~ False => (i -> c -> IO (Maybe a)) -> Resource c a i r e ops -> Resource c a i r e (View : ops) instance Show View instance Show Update instance Show ListAll instance Show Delete instance Show Add