-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A family of combinators for defining webservices APIs and serving them -- -- A family of combinators for defining webservices APIs and serving them -- -- You can learn about the basics in the getting started guide. -- -- Here's a runnable example, with comments, that defines a dummy -- API and implements a webserver that serves this API, using this -- package. @package servant-server @version 0.2.2 module Servant.Server.Internal toApplication :: RoutingApplication -> Application data RouteMismatch -- | the usual "not found" error NotFound :: RouteMismatch -- | a more informative "you just got the HTTP method wrong" error WrongMethod :: RouteMismatch -- | an even more informative "your json request body wasn't valid" error InvalidBody :: RouteMismatch -- |
-- > mempty = NotFound -- > -- > NotFound mappend x = x -- > WrongMethod mappend InvalidBody = InvalidBody -- > WrongMethod mappend _ = WrongMethod -- > InvalidBody mappend _ = InvalidBody ---- | A wrapper around Either RouteMismatch a. newtype RouteResult a RR :: Either RouteMismatch a -> RouteResult a routeResult :: RouteResult a -> Either RouteMismatch a failWith :: RouteMismatch -> RouteResult a succeedWith :: a -> RouteResult a isMismatch :: RouteResult a -> Bool -- | If we get a Right, it has precedence over everything else. -- -- This in particular means that if we could get several Rights, -- only the first we encounter would be taken into account. type RoutingApplication = Request -> (RouteResult Response -> IO ResponseReceived) -> IO ResponseReceived class HasServer layout where type family Server layout :: * route :: HasServer layout => Proxy layout -> Server layout -> RoutingApplication -- | A server for a :<|> b first tries to match the -- request again the route represented by a and if it fails -- tries b. You must provide a request handler for each route. -- --
-- type MyApi = "books" :> Get [Book] -- GET /books -- :<|> "books" :> ReqBody Book :> Post Book -- POST /books -- -- server :: Server MyApi -- server = listAllBooks :<|> postBook -- where listAllBooks = ... -- postBook book = ... --captured :: FromText a => proxy (Capture sym a) -> Text -> Maybe a -- | If you use Capture in one of the endpoints for your API, this -- automatically requires your server-side handler to be a function that -- takes an argument of the type specified by the Capture. This -- lets servant worry about getting it from the URL and turning it into a -- value of the type you specify. -- -- You can control how it'll be converted from Text to your type -- by simply providing an instance of FromText for your type. -- -- Example: -- --
-- type MyApi = "books" :> Capture "isbn" Text :> Get Book -- -- server :: Server MyApi -- server = getBook -- where getBook :: Text -> EitherT (Int, String) IO Book -- getBook isbn = ... ---- | If you have a Delete endpoint in your API, the handler for this -- endpoint is meant to delete a resource. -- -- The code of the handler will, just like for Get, Post -- and Put, run in EitherT (Int, String) IO (). The -- Int represents the status code and the String a message -- to be returned. You can use left to painlessly error out if the -- conditions for a successful deletion are not met. -- | When implementing the handler for a Get endpoint, just like for -- Delete, Post and Put, the handler code runs in -- the EitherT (Int, String) IO monad, where the Int -- represents the status code and the String a message, returned -- in case of failure. You can quite handily use left to quickly -- fail if some conditions are not met. -- -- If successfully returning a value, we just require that its type has a -- ToJSON instance and servant takes care of encoding it for you, -- yielding status code 200 along the way. -- | If you use Header in one of the endpoints for your API, this -- automatically requires your server-side handler to be a function that -- takes an argument of the type specified by Header. This lets -- servant worry about extracting it from the request and turning it into -- a value of the type you specify. -- -- All it asks is for a FromText instance. -- -- Example: -- --
-- newtype Referer = Referer Text -- deriving (Eq, Show, FromText, ToText) -- -- -- GET /view-my-referer -- type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get Referer -- -- server :: Server MyApi -- server = viewReferer -- where viewReferer :: Referer -> EitherT (Int, String) IO referer -- viewReferer referer = return referer ---- | When implementing the handler for a Post endpoint, just like -- for Delete, Get and Put, the handler code runs in -- the EitherT (Int, String) IO monad, where the Int -- represents the status code and the String a message, returned -- in case of failure. You can quite handily use left to quickly -- fail if some conditions are not met. -- -- If successfully returning a value, we just require that its type has a -- ToJSON instance and servant takes care of encoding it for you, -- yielding status code 201 along the way. -- | When implementing the handler for a Put endpoint, just like for -- Delete, Get and Post, the handler code runs in -- the EitherT (Int, String) IO monad, where the Int -- represents the status code and the String a message, returned -- in case of failure. You can quite handily use left to quickly -- fail if some conditions are not met. -- -- If successfully returning a value, we just require that its type has a -- ToJSON instance and servant takes care of encoding it for you, -- yielding status code 200 along the way. -- | If you use QueryParam "author" Text in one of the -- endpoints for your API, this automatically requires your server-side -- handler to be a function that takes an argument of type -- Maybe Text. -- -- This lets servant worry about looking it up in the query string and -- turning it into a value of the type you specify, enclosed in -- Maybe, because it may not be there and servant would then hand -- you Nothing. -- -- You can control how it'll be converted from Text to your type -- by simply providing an instance of FromText for your type. -- -- Example: -- --
-- type MyApi = "books" :> QueryParam "author" Text :> Get [Book] -- -- server :: Server MyApi -- server = getBooksBy -- where getBooksBy :: Maybe Text -> EitherT (Int, String) IO [Book] -- getBooksBy Nothing = ...return all books... -- getBooksBy (Just author) = ...return books by the given author... ---- | If you use QueryParams "authors" Text in one of the -- endpoints for your API, this automatically requires your server-side -- handler to be a function that takes an argument of type -- [Text]. -- -- This lets servant worry about looking up 0 or more values in the query -- string associated to authors and turning each of them into a -- value of the type you specify. -- -- You can control how the individual values are converted from -- Text to your type by simply providing an instance of -- FromText for your type. -- -- Example: -- --
-- type MyApi = "books" :> QueryParams "authors" Text :> Get [Book] -- -- server :: Server MyApi -- server = getBooksBy -- where getBooksBy :: [Text] -> EitherT (Int, String) IO [Book] -- getBooksBy authors = ...return all books by these authors... ---- | If you use QueryFlag "published" in one of the -- endpoints for your API, this automatically requires your server-side -- handler to be a function that takes an argument of type Bool. -- -- Example: -- --
-- type MyApi = "books" :> QueryFlag "published" :> Get [Book] -- -- server :: Server MyApi -- server = getBooks -- where getBooks :: Bool -> EitherT (Int, String) IO [Book] -- getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument... ---- | Just pass the request to the underlying application and serve its -- response. -- -- Example: -- --
-- type MyApi = "images" :> Raw -- -- server :: Server MyApi -- server = serveDirectory "/var/www/images" ---- | If you use ReqBody in one of the endpoints for your API, this -- automatically requires your server-side handler to be a function that -- takes an argument of the type specified by ReqBody. This lets -- servant worry about extracting it from the request and turning it into -- a value of the type you specify. -- -- All it asks is for a FromJSON instance. -- -- Example: -- --
-- type MyApi = "books" :> ReqBody Book :> Post Book -- -- server :: Server MyApi -- server = postBook -- where postBook :: Book -> EitherT (Int, String) IO Book -- postBook book = ...insert into your db... ---- | Make sure the incoming request starts with "/path", strip it -- and pass the rest of the request path to sublayout. instance Eq RouteMismatch instance Show RouteMismatch instance Eq a => Eq (RouteResult a) instance Show a => Show (RouteResult a) instance (KnownSymbol path, HasServer sublayout) => HasServer (path :> sublayout) instance (FromJSON a, HasServer sublayout) => HasServer (ReqBody a :> sublayout) instance HasServer Raw instance (KnownSymbol sym, HasServer sublayout) => HasServer (QueryFlag sym :> sublayout) instance (KnownSymbol sym, FromText a, HasServer sublayout) => HasServer (QueryParams sym a :> sublayout) instance (KnownSymbol sym, FromText a, HasServer sublayout) => HasServer (QueryParam sym a :> sublayout) instance ToJSON a => HasServer (Put a) instance ToJSON a => HasServer (Post a) instance (KnownSymbol sym, FromText a, HasServer sublayout) => HasServer (Header sym a :> sublayout) instance ToJSON result => HasServer (Get result) instance HasServer Delete instance (KnownSymbol capture, FromText a, HasServer sublayout) => HasServer (Capture capture a :> sublayout) instance (HasServer a, HasServer b) => HasServer (a :<|> b) instance Monoid (RouteResult a) instance Monoid RouteMismatch -- | This module lets you implement Servers for defined APIs. You'll -- most likely just need serve. module Servant.Server -- | serve allows you to implement an API and produce a wai -- Application. -- -- Example: -- --
-- type MyApi = "books" :> Get [Book] -- GET /books -- :<|> "books" :> ReqBody Book :> Post Book -- POST /books -- -- server :: Server MyApi -- server = listAllBooks :<|> postBook -- where listAllBooks = ... -- postBook book = ... -- -- app :: Application -- app = serve myApi server -- -- main :: IO () -- main = Network.Wai.Handler.Warp.run 8080 app --serve :: HasServer layout => Proxy layout -> Server layout -> Application class HasServer layout where type family Server layout :: * route :: HasServer layout => Proxy layout -> Server layout -> RoutingApplication -- | This module defines a sever-side handler that lets you serve static -- files. -- --
-- type MyApi = "static" :> Raw -- -- server :: Server MyApi -- server = serveDirectory "/var/www" ---- -- would capture any request to /static/<something> and -- look for <something> under /var/www. -- -- It will do its best to guess the MIME type for that file, based on the -- extension, and send an appropriate Content-Type header if -- possible. -- -- If your goal is to serve HTML, CSS and Javascript files that use the -- rest of the API as a webapp backend, you will most likely not want the -- static files to be hidden behind a /static/ prefix. In that -- case, remember to put the serveDirectory handler in the last -- position, because servant will try to match the handlers in -- order. serveDirectory :: FilePath -> Server Raw module Servant -- | A concrete, poly-kinded proxy type data Proxy (t :: k) :: k -> * Proxy :: Proxy