servant-generic 0.1.0.0 → 0.1.0.1
raw patch · 3 files changed
+52/−12 lines, 3 filesdep +network-uridep ~basedep ~servantPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
Dependencies added: network-uri
Dependency ranges changed: base, servant
API changes (from Hackage documentation)
+ Servant.Generic: data AsLink
+ Servant.Generic: fieldLink :: forall routes endpoint. (IsElem endpoint (ToServant (routes AsApi)), HasLink endpoint) => (routes AsApi -> endpoint) -> MkLink endpoint
+ Servant.Generic: fromServant :: GenericProduct a => ToServant a -> a
+ Servant.Generic: gfromServant :: GProduct f => GToServant f -> f p
Files
- examples/Basic.hs +15/−0
- servant-generic.cabal +6/−8
- src/Servant/Generic.hs +31/−4
examples/Basic.hs view
@@ -2,17 +2,22 @@ {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} +import Data.Monoid import Servant import Servant.Generic import qualified Data.Text as T import Data.Text (Text) import Network.Wai.Handler.Warp (run) import System.Timeout+import Network.URI data Site route = Site { about :: route :- "about" :> Get '[PlainText] Text+ , aboot :: route :-+ "aboot" :> Get '[PlainText] Text , faq :: route :- "faq" :> Get '[PlainText] Text , subSite :: route :-@@ -39,6 +44,7 @@ siteServer :: Site AsServer siteServer = Site { about = return "about"+ , aboot = return ("did you mean " <> showLink (fieldLink about) <> "?") , faq = return "faq" , subSite = toServant subSiteServer , home = return "So long and thanks for all the :<|>"@@ -51,3 +57,12 @@ -- just to use this example as a test, run the server for one second Nothing <- timeout 1000000 runServer return ()++-- Servant changed the instance of MkLink in 0.10.+#if MIN_VERSION_servant(0,10,0)+showLink :: Link -> Text+showLink = toUrlPiece+#else+showLink :: URI -> Text+showLink uri = T.pack (uriToString id uri "")+#endif
servant-generic.cabal view
@@ -1,10 +1,7 @@--- Initial servant-generic.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/- name: servant-generic-version: 0.1.0.0+version: 0.1.0.1 synopsis: Specify Servant APIs with records.-description: See README.+description: Specify Servant APIs with records instead of @:\<|\>@ trees. See the <https://github.com/chpatrick/servant-generic/blob/master/README.md#tldr README> for more information. license: MIT license-file: LICENSE author: Patrick Chilton@@ -23,7 +20,7 @@ exposed-modules: Servant.Generic -- other-modules: -- other-extensions: - build-depends: base >=4.7 && <4.10,+ build-depends: base >=4.7 && <4.11, servant >= 0.7.1, servant-server >= 0.7.1 hs-source-dirs: src@@ -34,9 +31,10 @@ type: exitcode-stdio-1.0 main-is: examples/Basic.hs default-language: Haskell2010- build-depends: base >=4.7 && <4.10,+ build-depends: base >=4.7 && <4.11, servant >= 0.7.1, servant-server >= 0.7.1, servant-generic, text,- warp+ warp,+ network-uri
src/Servant/Generic.hs view
@@ -8,18 +8,23 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE DataKinds #-}- +{-# LANGUAGE ScopedTypeVariables #-}+ module Servant.Generic ( (:-) , AsServerT , AsServer , AsApi+ , AsLink , ToServant , toServant+ , fromServant , GenericProduct -- * Internals , GProduct(..) , Generic(..)++ , fieldLink ) where import GHC.Generics@@ -29,24 +34,28 @@ class GProduct f where type GToServant f gtoServant :: f p -> GToServant f+ gfromServant :: GToServant f -> f p instance GProduct f => GProduct (M1 i c f) where type GToServant (M1 i c f) = GToServant f gtoServant (M1 x) = gtoServant x+ gfromServant x = M1 (gfromServant x) instance (GProduct l, GProduct r) => GProduct (l :*: r) where type GToServant (l :*: r) = GToServant l :<|> GToServant r gtoServant (l :*: r) = gtoServant l :<|> gtoServant r+ gfromServant (l :<|> r) = gfromServant l :*: gfromServant r instance GProduct (K1 i c) where type GToServant (K1 i c) = c gtoServant (K1 x) = x+ gfromServant x = K1 x type GenericProduct a = (Generic a, GProduct (Rep a)) -- | Turns a generic product type into a linear tree of `:<|>` combinators. -- For example, given--- +-- -- @ -- data Foo route = Foo -- { foo :: route :-@@ -55,7 +64,7 @@ -- Get '[PlainText] Text -- } -- @--- +-- -- @ ToServant (Foo AsApi) ~ Get '[PlainText] Text :\<|\> Get '[PlainText] Text @ type ToServant a = GToServant (Rep a) @@ -63,16 +72,34 @@ toServant :: GenericProduct a => a -> ToServant a toServant = gtoServant . from +-- | Inverse of `toServant`.+--+-- This can be used to turn 'generated' values such as client functions into records.+--+-- You may need to provide a type signature for the /output/ type (your record type).+fromServant :: GenericProduct a => ToServant a -> a+fromServant = to . gfromServant+ -- | A type family that applies an appropriate type family to the @api@ parameter. -- For example, passing `AsApi` will leave @api@ untouched, while @`AsServerT` m@ will produce @`ServerT` api m@. type family mode :- api-infixl 8 :-+infixl 3 :- -- | A type that specifies that an API record contains an API definition. Only useful at type-level. data AsApi type instance AsApi :- api = api +-- | A type that specifies that an API record contains a set of links.+--+-- (Useful since servant 0.12)+data AsLink+type instance AsLink :- api = MkLink api+ -- | A type that specifies that an API record contains a server implementation. data AsServerT (m :: * -> *) type instance AsServerT m :- api = ServerT api m type AsServer = AsServerT Handler++-- | Given an API record field, create a link for that route. Only the field's type is used.+fieldLink :: forall routes endpoint. (IsElem endpoint (ToServant (routes AsApi)), HasLink endpoint) => (routes AsApi -> endpoint) -> MkLink endpoint+fieldLink _ = safeLink (Proxy :: Proxy (ToServant (routes AsApi))) (Proxy :: Proxy endpoint)