Merge tag 'v0.8' into client-ghcjs_7.1
This commit is contained in:
commit
187fe5b139
29 changed files with 165 additions and 139 deletions
|
@ -1,5 +1,5 @@
|
|||
name: tutorial
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: The servant tutorial
|
||||
homepage: http://haskell-servant.readthedocs.org/
|
||||
license: BSD3
|
||||
|
@ -25,11 +25,11 @@ library
|
|||
, directory
|
||||
, blaze-markup
|
||||
, containers
|
||||
, servant == 0.7.*
|
||||
, servant-server == 0.7.*
|
||||
, servant-client == 0.7.*
|
||||
, servant-docs == 0.7.*
|
||||
, servant-js == 0.7.*
|
||||
, servant == 0.8.*
|
||||
, servant-server == 0.8.*
|
||||
, servant-client == 0.8.*
|
||||
, servant-docs == 0.8.*
|
||||
, servant-js == 0.8.*
|
||||
, warp
|
||||
, http-media
|
||||
, lucid
|
||||
|
@ -54,6 +54,7 @@ test-suite spec
|
|||
default-language: Haskell2010
|
||||
hs-source-dirs: test
|
||||
main-is: Spec.hs
|
||||
other-modules: JavascriptSpec
|
||||
build-depends: base == 4.*
|
||||
, tutorial
|
||||
, hspec
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant-client
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: automatical derivation of querying functions for servant webservices
|
||||
description:
|
||||
This library lets you derive automatically Haskell functions that
|
||||
|
@ -44,29 +44,29 @@ library
|
|||
other-modules:
|
||||
Servant.Client.PerformRequest.GHC
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, aeson
|
||||
, attoparsec
|
||||
, base64-bytestring
|
||||
, bytestring
|
||||
, case-insensitive
|
||||
, exceptions
|
||||
, http-api-data >= 0.1 && < 0.3
|
||||
, http-client <0.5
|
||||
, http-client-tls
|
||||
, http-media
|
||||
, http-types
|
||||
, network-uri >= 2.6
|
||||
, safe
|
||||
, servant == 0.7.*
|
||||
, string-conversions
|
||||
, text
|
||||
, transformers
|
||||
, transformers-compat
|
||||
base >= 4.7 && < 4.10
|
||||
, aeson >= 0.7 && < 0.12
|
||||
, attoparsec >= 0.12 && < 0.14
|
||||
, base64-bytestring >= 1.0.0.1 && < 1.1
|
||||
, bytestring >= 0.10 && < 0.11
|
||||
, exceptions >= 0.8 && < 0.9
|
||||
, http-api-data >= 0.1 && < 0.3
|
||||
, http-client >= 0.4.18.1 && < 0.6
|
||||
, http-client-tls >= 0.2.2 && < 0.4
|
||||
, http-media >= 0.6.2 && < 0.7
|
||||
, http-types >= 0.8.6 && < 0.10
|
||||
, network-uri >= 2.6 && < 2.7
|
||||
, safe >= 0.3.9 && < 0.4
|
||||
, servant == 0.8.*
|
||||
, string-conversions >= 0.3 && < 0.5
|
||||
, text >= 1.2 && < 1.3
|
||||
, transformers >= 0.3 && < 0.6
|
||||
, transformers-compat >= 0.4 && < 0.6
|
||||
if impl(ghcjs)
|
||||
build-depends:
|
||||
ghcjs-base
|
||||
, ghcjs-prim
|
||||
, case-insensitive
|
||||
hs-source-dirs: src
|
||||
default-language: Haskell2010
|
||||
ghc-options: -Wall
|
||||
|
@ -77,6 +77,8 @@ library
|
|||
test-suite spec
|
||||
type: exitcode-stdio-1.0
|
||||
ghc-options: -Wall -fno-warn-name-shadowing
|
||||
if impl(ghc >= 8.0)
|
||||
ghc-options: -Wno-redundant-constraints
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: test, src
|
||||
main-is: Spec.hs
|
||||
|
@ -110,8 +112,8 @@ test-suite spec
|
|||
, HUnit
|
||||
, network >= 2.6
|
||||
, QuickCheck >= 2.7
|
||||
, servant == 0.7.*
|
||||
, servant-server == 0.7.*
|
||||
, servant == 0.8.*
|
||||
, servant-server == 0.8.*
|
||||
, text
|
||||
, wai
|
||||
, warp
|
||||
|
|
|
@ -112,9 +112,8 @@ performRequest :: Method -> Req -> Manager -> BaseUrl
|
|||
performRequest reqMethod req manager reqHost = do
|
||||
partialRequest <- liftIO $ reqToRequest req reqHost
|
||||
|
||||
let request = partialRequest { Client.method = reqMethod
|
||||
, checkStatus = \ _status _headers _cookies -> Nothing
|
||||
}
|
||||
let request = disableStatusCheck $
|
||||
partialRequest { Client.method = reqMethod }
|
||||
|
||||
eResponse <- liftIO $ performHttpRequest manager request
|
||||
case eResponse of
|
||||
|
@ -135,6 +134,12 @@ performRequest reqMethod req manager reqHost = do
|
|||
throwE $ FailureResponse status ct body
|
||||
return (status_code, body, ct, hdrs, response)
|
||||
|
||||
disableStatusCheck :: Request -> Request
|
||||
#if MIN_VERSION_http_client(0,5,0)
|
||||
disableStatusCheck req = req { checkResponse = \ _req _res -> return () }
|
||||
#else
|
||||
disableStatusCheck req = req { checkStatus = \ _status _headers _cookies -> Nothing }
|
||||
#endif
|
||||
|
||||
performRequestCT :: MimeUnrender ct result =>
|
||||
Proxy ct -> Method -> Req -> Manager -> BaseUrl
|
||||
|
|
|
@ -6,6 +6,7 @@ executables:
|
|||
other-modules: []
|
||||
dependencies:
|
||||
- base
|
||||
- base-compat
|
||||
- aeson
|
||||
- base64-bytestring
|
||||
- bytestring
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- This file has been generated from package.yaml by hpack version 0.13.0.
|
||||
-- This file has been generated from package.yaml by hpack version 0.14.0.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
|
@ -17,6 +17,7 @@ executable testServer
|
|||
../../../include
|
||||
build-depends:
|
||||
base
|
||||
, base-compat
|
||||
, aeson
|
||||
, base64-bytestring
|
||||
, bytestring
|
||||
|
|
|
@ -81,7 +81,7 @@ type TestApi =
|
|||
:<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] (Headers '[Header "X-Example" Int] Greet)
|
||||
|
||||
-- DELETE /greet/:greetid
|
||||
:<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] ()
|
||||
:<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent
|
||||
|
||||
testApi :: Proxy TestApi
|
||||
testApi = Proxy
|
||||
|
@ -91,7 +91,7 @@ testApi = Proxy
|
|||
-- notes.
|
||||
extra :: ExtraInfo TestApi
|
||||
extra =
|
||||
extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] ())) $
|
||||
extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent)) $
|
||||
defAction & headers <>~ ["unicorns"]
|
||||
& notes <>~ [ DocNote "Title" ["This is some text"]
|
||||
, DocNote "Second secton" ["And some more"]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant-docs
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: generate API docs for your servant webservice
|
||||
description:
|
||||
Library for generating API docs from a servant API definition.
|
||||
|
@ -42,7 +42,7 @@ library
|
|||
, http-media >= 0.6
|
||||
, http-types >= 0.7
|
||||
, lens
|
||||
, servant == 0.7.*
|
||||
, servant == 0.8.*
|
||||
, string-conversions
|
||||
, text
|
||||
, unordered-containers
|
||||
|
|
|
@ -833,7 +833,7 @@ instance (ToAuthInfo (BasicAuth realm usr), HasDocs api) => HasDocs (BasicAuth r
|
|||
action' = over authInfo (|> toAuthInfo authProxy) action
|
||||
|
||||
-- ToSample instances for simple types
|
||||
instance ToSample ()
|
||||
instance ToSample NoContent
|
||||
instance ToSample Bool
|
||||
instance ToSample Ordering
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant-foreign
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: Helpers for generating clients for servant APIs in any programming language
|
||||
description:
|
||||
Helper types and functions for generating client functions for servant APIs in any programming language
|
||||
|
@ -32,7 +32,7 @@ library
|
|||
, Servant.Foreign.Inflections
|
||||
build-depends: base == 4.*
|
||||
, lens == 4.*
|
||||
, servant == 0.7.*
|
||||
, servant == 0.8.*
|
||||
, text >= 1.2 && < 1.3
|
||||
, http-types
|
||||
hs-source-dirs: src
|
||||
|
|
|
@ -169,11 +169,11 @@ type family Elem (a :: *) (ls::[*]) :: Constraint where
|
|||
-- > getEndpoints api = listFromAPI (Proxy :: Proxy LangX) (Proxy :: Proxy Text) api
|
||||
--
|
||||
-- > -- If language __X__ is dynamically typed then you can use
|
||||
-- > -- a predefined NoTypes parameter with the () output type:
|
||||
-- > -- a predefined NoTypes parameter with the NoContent output type:
|
||||
--
|
||||
-- > getEndpoints :: (HasForeign NoTypes () api, GenerateList Text (Foreign () api))
|
||||
-- > => Proxy api -> [Req ()]
|
||||
-- > getEndpoints api = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy ()) api
|
||||
-- > getEndpoints :: (HasForeign NoTypes NoContent api, GenerateList Text (Foreign NoContent api))
|
||||
-- > => Proxy api -> [Req NoContent]
|
||||
-- > getEndpoints api = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy NoContent) api
|
||||
-- >
|
||||
--
|
||||
class HasForeignType lang ftype a where
|
||||
|
@ -181,8 +181,8 @@ class HasForeignType lang ftype a where
|
|||
|
||||
data NoTypes
|
||||
|
||||
instance HasForeignType NoTypes () ftype where
|
||||
typeFor _ _ _ = ()
|
||||
instance HasForeignType NoTypes NoContent ftype where
|
||||
typeFor _ _ _ = NoContent
|
||||
|
||||
class HasForeign lang ftype (api :: *) where
|
||||
type Foreign ftype api :: *
|
||||
|
|
|
@ -26,7 +26,7 @@ camelCaseSpec = describe "camelCase" $ do
|
|||
|
||||
data LangX
|
||||
|
||||
instance HasForeignType LangX String () where
|
||||
instance HasForeignType LangX String NoContent where
|
||||
typeFor _ _ _ = "voidX"
|
||||
|
||||
instance HasForeignType LangX String Int where
|
||||
|
@ -43,9 +43,9 @@ instance OVERLAPPABLE_ HasForeignType LangX String a => HasForeignType LangX Str
|
|||
|
||||
type TestApi
|
||||
= "test" :> Header "header" [String] :> QueryFlag "flag" :> Get '[JSON] Int
|
||||
:<|> "test" :> QueryParam "param" Int :> ReqBody '[JSON] [String] :> Post '[JSON] ()
|
||||
:<|> "test" :> QueryParams "params" Int :> ReqBody '[JSON] String :> Put '[JSON] ()
|
||||
:<|> "test" :> Capture "id" Int :> Delete '[JSON] ()
|
||||
:<|> "test" :> QueryParam "param" Int :> ReqBody '[JSON] [String] :> Post '[JSON] NoContent
|
||||
:<|> "test" :> QueryParams "params" Int :> ReqBody '[JSON] String :> Put '[JSON] NoContent
|
||||
:<|> "test" :> Capture "id" Int :> Delete '[JSON] NoContent
|
||||
|
||||
testApi :: [Req String]
|
||||
testApi = listFromAPI (Proxy :: Proxy LangX) (Proxy :: Proxy String) (Proxy :: Proxy TestApi)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant-js
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: Automatically derive javascript functions to query servant webservices.
|
||||
description:
|
||||
Automatically derive javascript functions to query servant webservices.
|
||||
|
@ -45,7 +45,8 @@ library
|
|||
, base-compat >= 0.9
|
||||
, charset >= 0.3
|
||||
, lens >= 4
|
||||
, servant-foreign == 0.7.*
|
||||
, servant-foreign == 0.8.*
|
||||
, servant == 0.8.*
|
||||
, text >= 1.2 && < 1.3
|
||||
|
||||
hs-source-dirs: src
|
||||
|
@ -67,8 +68,8 @@ executable counter
|
|||
, aeson >= 0.7 && < 0.12
|
||||
, filepath >= 1
|
||||
, lens >= 4
|
||||
, servant == 0.7.*
|
||||
, servant-server == 0.7.*
|
||||
, servant == 0.8.*
|
||||
, servant-server == 0.8.*
|
||||
, servant-js
|
||||
, stm
|
||||
, transformers
|
||||
|
|
|
@ -118,6 +118,7 @@ import Prelude hiding (writeFile)
|
|||
import Data.Proxy
|
||||
import Data.Text
|
||||
import Data.Text.IO (writeFile)
|
||||
import Servant.API.ContentTypes
|
||||
import Servant.JS.Angular
|
||||
import Servant.JS.Axios
|
||||
import Servant.JS.Internal
|
||||
|
@ -128,22 +129,22 @@ import Servant.Foreign (listFromAPI)
|
|||
-- | Generate the data necessary to generate javascript code
|
||||
-- for all the endpoints of an API, as ':<|>'-separated values
|
||||
-- of type 'AjaxReq'.
|
||||
javascript :: HasForeign NoTypes () api => Proxy api -> Foreign () api
|
||||
javascript p = foreignFor (Proxy :: Proxy NoTypes) (Proxy :: Proxy ()) p defReq
|
||||
javascript :: HasForeign NoTypes NoContent api => Proxy api -> Foreign NoContent api
|
||||
javascript p = foreignFor (Proxy :: Proxy NoTypes) (Proxy :: Proxy NoContent) p defReq
|
||||
|
||||
-- | Directly generate all the javascript functions for your API
|
||||
-- from a 'Proxy' for your API type. You can then write it to
|
||||
-- a file or integrate it in a page, for example.
|
||||
jsForAPI :: (HasForeign NoTypes () api, GenerateList () (Foreign () api))
|
||||
jsForAPI :: (HasForeign NoTypes NoContent api, GenerateList NoContent (Foreign NoContent api))
|
||||
=> Proxy api -- ^ proxy for your API type
|
||||
-> JavaScriptGenerator -- ^ js code generator to use (angular, vanilla js, jquery, others)
|
||||
-> Text -- ^ a text that you can embed in your pages or write to a file
|
||||
jsForAPI p gen = gen (listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy ()) p)
|
||||
jsForAPI p gen = gen (listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy NoContent) p)
|
||||
|
||||
-- | Directly generate all the javascript functions for your API
|
||||
-- from a 'Proxy' for your API type using the given generator
|
||||
-- and write the resulting code to a file at the given path.
|
||||
writeJSForAPI :: (HasForeign NoTypes () api, GenerateList () (Foreign () api))
|
||||
writeJSForAPI :: (HasForeign NoTypes NoContent api, GenerateList NoContent (Foreign NoContent api))
|
||||
=> Proxy api -- ^ proxy for your API type
|
||||
-> JavaScriptGenerator -- ^ js code generator to use (angular, vanilla js, jquery, others)
|
||||
-> FilePath -- ^ path to the file you want to write the resulting javascript code into
|
||||
|
|
|
@ -54,12 +54,12 @@ import qualified Data.Text as T
|
|||
import Data.Text (Text)
|
||||
import Servant.Foreign
|
||||
|
||||
type AjaxReq = Req ()
|
||||
type AjaxReq = Req NoContent
|
||||
|
||||
-- A 'JavascriptGenerator' just takes the data found in the API type
|
||||
-- for each endpoint and generates Javascript code in a Text. Several
|
||||
-- generators are available in this package.
|
||||
type JavaScriptGenerator = [Req ()] -> Text
|
||||
type JavaScriptGenerator = [Req NoContent] -> Text
|
||||
|
||||
-- | This structure is used by specific implementations to let you
|
||||
-- customize the output
|
||||
|
|
|
@ -21,6 +21,7 @@ import Prelude.Compat
|
|||
import Test.Hspec hiding (shouldContain, shouldNotContain)
|
||||
|
||||
import Servant.API.Internal.Test.ComprehensiveAPI
|
||||
import Servant.API.ContentTypes
|
||||
import Servant.JS
|
||||
import Servant.JS.Internal
|
||||
import qualified Servant.JS.Angular as NG
|
||||
|
@ -105,7 +106,7 @@ a `shouldNotContain` b = shouldNotSatisfy a (T.isInfixOf b)
|
|||
|
||||
axiosSpec :: Spec
|
||||
axiosSpec = describe specLabel $ do
|
||||
let reqList = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy ()) (Proxy :: Proxy TestAPI)
|
||||
let reqList = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy NoContent) (Proxy :: Proxy TestAPI)
|
||||
it "should add withCredentials when needed" $ do
|
||||
let jsText = genJS withCredOpts $ reqList
|
||||
output jsText
|
||||
|
@ -129,7 +130,7 @@ axiosSpec = describe specLabel $ do
|
|||
|
||||
angularSpec :: TestNames -> Spec
|
||||
angularSpec test = describe specLabel $ do
|
||||
let reqList = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy ()) (Proxy :: Proxy TestAPI)
|
||||
let reqList = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy NoContent) (Proxy :: Proxy TestAPI)
|
||||
it "should implement a service globally" $ do
|
||||
let jsText = genJS reqList
|
||||
output jsText
|
||||
|
|
|
@ -16,6 +16,7 @@ import Data.Monoid
|
|||
import Data.Proxy
|
||||
import Data.Text (pack)
|
||||
import GHC.TypeLits
|
||||
import Servant.API.ContentTypes
|
||||
import Servant.JS.Internal
|
||||
|
||||
-- | This is a hypothetical combinator that fetches an Authorization header.
|
||||
|
@ -23,13 +24,13 @@ import Servant.JS.Internal
|
|||
-- using -- Basic, Digest, whatever.
|
||||
data Authorization (sym :: Symbol) a
|
||||
|
||||
instance (KnownSymbol sym, HasForeign lang () api)
|
||||
=> HasForeign lang () (Authorization sym a :> api) where
|
||||
type Foreign () (Authorization sym a :> api) = Foreign () api
|
||||
instance (KnownSymbol sym, HasForeign lang NoContent api)
|
||||
=> HasForeign lang NoContent (Authorization sym a :> api) where
|
||||
type Foreign NoContent (Authorization sym a :> api) = Foreign NoContent api
|
||||
|
||||
foreignFor lang ftype Proxy req = foreignFor lang ftype (Proxy :: Proxy api) $
|
||||
req & reqHeaders <>~
|
||||
[ ReplaceHeaderArg (Arg "Authorization" ())
|
||||
[ ReplaceHeaderArg (Arg "Authorization" NoContent)
|
||||
$ tokenType (pack . symbolVal $ (Proxy :: Proxy sym)) ]
|
||||
where
|
||||
tokenType t = t <> " {Authorization}"
|
||||
|
@ -37,23 +38,23 @@ instance (KnownSymbol sym, HasForeign lang () api)
|
|||
-- | This is a combinator that fetches an X-MyLovelyHorse header.
|
||||
data MyLovelyHorse a
|
||||
|
||||
instance (HasForeign lang () api)
|
||||
=> HasForeign lang () (MyLovelyHorse a :> api) where
|
||||
type Foreign () (MyLovelyHorse a :> api) = Foreign () api
|
||||
instance (HasForeign lang NoContent api)
|
||||
=> HasForeign lang NoContent (MyLovelyHorse a :> api) where
|
||||
type Foreign NoContent (MyLovelyHorse a :> api) = Foreign NoContent api
|
||||
|
||||
foreignFor lang ftype Proxy req = foreignFor lang ftype (Proxy :: Proxy api) $
|
||||
req & reqHeaders <>~ [ ReplaceHeaderArg (Arg "X-MyLovelyHorse" ()) tpl ]
|
||||
req & reqHeaders <>~ [ ReplaceHeaderArg (Arg "X-MyLovelyHorse" NoContent) tpl ]
|
||||
where
|
||||
tpl = "I am good friends with {X-MyLovelyHorse}"
|
||||
|
||||
-- | This is a combinator that fetches an X-WhatsForDinner header.
|
||||
data WhatsForDinner a
|
||||
|
||||
instance (HasForeign lang () api)
|
||||
=> HasForeign lang () (WhatsForDinner a :> api) where
|
||||
type Foreign () (WhatsForDinner a :> api) = Foreign () api
|
||||
instance (HasForeign lang NoContent api)
|
||||
=> HasForeign lang NoContent (WhatsForDinner a :> api) where
|
||||
type Foreign NoContent (WhatsForDinner a :> api) = Foreign NoContent api
|
||||
|
||||
foreignFor lang ftype Proxy req = foreignFor lang ftype (Proxy :: Proxy api) $
|
||||
req & reqHeaders <>~ [ ReplaceHeaderArg (Arg "X-WhatsForDinner" ()) tpl ]
|
||||
req & reqHeaders <>~ [ ReplaceHeaderArg (Arg "X-WhatsForDinner" NoContent) tpl ]
|
||||
where
|
||||
tpl = "I would like {X-WhatsForDinner} with a cherry on top."
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant-mock
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: Derive a mock server for free from your servant API types
|
||||
description:
|
||||
Derive a mock server for free from your servant API types
|
||||
|
@ -31,8 +31,8 @@ library
|
|||
base >=4.7 && <5,
|
||||
bytestring >= 0.10 && <0.11,
|
||||
http-types >= 0.8 && <0.10,
|
||||
servant == 0.7.*,
|
||||
servant-server == 0.7.*,
|
||||
servant == 0.8.*,
|
||||
servant-server == 0.8.*,
|
||||
transformers >= 0.3 && <0.6,
|
||||
QuickCheck >= 2.7 && <2.9,
|
||||
wai >= 3.0 && <3.3
|
||||
|
|
|
@ -180,3 +180,6 @@ instance Arbitrary (HList '[]) where
|
|||
instance (Arbitrary a, Arbitrary (HList hs))
|
||||
=> Arbitrary (HList (Header h a ': hs)) where
|
||||
arbitrary = HCons <$> fmap Header arbitrary <*> arbitrary
|
||||
|
||||
instance Arbitrary NoContent where
|
||||
arbitrary = pure NoContent
|
||||
|
|
|
@ -34,7 +34,7 @@ type TestApi =
|
|||
:<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] Greet
|
||||
|
||||
-- DELETE /greet/:greetid
|
||||
:<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] ()
|
||||
:<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent
|
||||
|
||||
testApi :: Proxy TestApi
|
||||
testApi = Proxy
|
||||
|
@ -54,7 +54,7 @@ server = helloH :<|> postGreetH :<|> deleteGreetH
|
|||
|
||||
postGreetH greet = return greet
|
||||
|
||||
deleteGreetH _ = return ()
|
||||
deleteGreetH _ = return NoContent
|
||||
|
||||
-- Turn the server into a WAI app. 'serve' is provided by servant,
|
||||
-- more precisely by the Servant.Server module.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant-server
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: A family of combinators for defining webservices APIs and serving them
|
||||
description:
|
||||
A family of combinators for defining webservices APIs and serving them
|
||||
|
@ -45,31 +45,31 @@ library
|
|||
Servant.Server.Internal.ServantErr
|
||||
Servant.Utils.StaticFiles
|
||||
build-depends:
|
||||
base >= 4.7 && < 5
|
||||
, base-compat >= 0.9
|
||||
base >= 4.7 && < 4.10
|
||||
, base-compat >= 0.9 && < 0.10
|
||||
, aeson >= 0.7 && < 0.12
|
||||
, attoparsec >= 0.12 && < 0.14
|
||||
, base64-bytestring == 1.0.*
|
||||
, base64-bytestring >= 1.0 && < 1.1
|
||||
, bytestring >= 0.10 && < 0.11
|
||||
, containers >= 0.5 && < 0.6
|
||||
, http-api-data >= 0.1 && < 0.3
|
||||
, http-types >= 0.8 && < 0.10
|
||||
, network-uri >= 2.6 && < 2.7
|
||||
, mtl >= 2 && < 3
|
||||
, mtl >= 2 && < 2.3
|
||||
, network >= 2.6 && < 2.7
|
||||
, safe >= 0.3 && < 0.4
|
||||
, servant == 0.7.*
|
||||
, servant == 0.8.*
|
||||
, split >= 0.2 && < 0.3
|
||||
, string-conversions >= 0.3 && < 0.5
|
||||
, system-filepath >= 0.4 && < 0.5
|
||||
, filepath >= 1
|
||||
, filepath >= 1 && < 1.5
|
||||
, text >= 1.2 && < 1.3
|
||||
, transformers >= 0.3 && < 0.6
|
||||
, transformers-compat>= 0.4
|
||||
, transformers-compat>= 0.4 && < 0.6
|
||||
, wai >= 3.0 && < 3.3
|
||||
, wai-app-static >= 3.1 && < 3.2
|
||||
, warp >= 3.0 && < 3.3
|
||||
, word8 == 0.1.*
|
||||
, word8 >= 0.1 && < 0.2
|
||||
|
||||
hs-source-dirs: src
|
||||
default-language: Haskell2010
|
||||
|
|
|
@ -147,7 +147,7 @@ serveWithContext p context server =
|
|||
-- For the following API
|
||||
--
|
||||
-- > type API =
|
||||
-- > "a" :> "d" :> Get '[JSON] ()
|
||||
-- > "a" :> "d" :> Get '[JSON] NoContent
|
||||
-- > :<|> "b" :> Capture "x" Int :> Get '[JSON] Bool
|
||||
-- > :<|> "c" :> Put '[JSON] Bool
|
||||
-- > :<|> "a" :> "e" :> Get '[JSON] Int
|
||||
|
|
|
@ -74,7 +74,7 @@ makeTrivialRouter :: (HasServer layout '[]) => Proxy layout -> Router ()
|
|||
makeTrivialRouter p =
|
||||
route p EmptyContext (emptyDelayed (FailFatal err501))
|
||||
|
||||
type End = Get '[JSON] ()
|
||||
type End = Get '[JSON] NoContent
|
||||
|
||||
-- The latter version looks more efficient,
|
||||
-- but the former should be compiled to the
|
||||
|
|
|
@ -340,19 +340,23 @@ reqBodySpec = describe "Servant.API.ReqBody" $ do
|
|||
-- * headerSpec {{{
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
type HeaderApi a = Header "MyHeader" a :> Delete '[JSON] ()
|
||||
type HeaderApi a = Header "MyHeader" a :> Delete '[JSON] NoContent
|
||||
headerApi :: Proxy (HeaderApi a)
|
||||
headerApi = Proxy
|
||||
|
||||
headerSpec :: Spec
|
||||
headerSpec = describe "Servant.API.Header" $ do
|
||||
|
||||
let expectsInt :: Maybe Int -> Handler ()
|
||||
expectsInt (Just x) = when (x /= 5) $ error "Expected 5"
|
||||
let expectsInt :: Maybe Int -> Handler NoContent
|
||||
expectsInt (Just x) = do
|
||||
when (x /= 5) $ error "Expected 5"
|
||||
return NoContent
|
||||
expectsInt Nothing = error "Expected an int"
|
||||
|
||||
let expectsString :: Maybe String -> Handler ()
|
||||
expectsString (Just x) = when (x /= "more from you") $ error "Expected more from you"
|
||||
let expectsString :: Maybe String -> Handler NoContent
|
||||
expectsString (Just x) = do
|
||||
when (x /= "more from you") $ error "Expected more from you"
|
||||
return NoContent
|
||||
expectsString Nothing = error "Expected a string"
|
||||
|
||||
with (return (serve headerApi expectsInt)) $ do
|
||||
|
@ -410,7 +414,7 @@ type AlternativeApi =
|
|||
:<|> "foo" :> Get '[PlainText] T.Text
|
||||
:<|> "bar" :> Post '[JSON] Animal
|
||||
:<|> "bar" :> Put '[JSON] Animal
|
||||
:<|> "bar" :> Delete '[JSON] ()
|
||||
:<|> "bar" :> Delete '[JSON] NoContent
|
||||
|
||||
alternativeApi :: Proxy AlternativeApi
|
||||
alternativeApi = Proxy
|
||||
|
@ -422,7 +426,7 @@ alternativeServer =
|
|||
:<|> return "a string"
|
||||
:<|> return jerry
|
||||
:<|> return jerry
|
||||
:<|> return ()
|
||||
:<|> return NoContent
|
||||
|
||||
alternativeSpec :: Spec
|
||||
alternativeSpec = do
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
0.8
|
||||
---
|
||||
|
||||
* Minor fixes, documentation changes and cabal tweaks
|
||||
|
||||
0.7.1
|
||||
-----
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: servant
|
||||
version: 0.7.1
|
||||
version: 0.8
|
||||
synopsis: A family of combinators for defining webservices APIs
|
||||
description:
|
||||
A family of combinators for defining webservices APIs and serving them
|
||||
|
@ -49,22 +49,22 @@ library
|
|||
Servant.Utils.Links
|
||||
Servant.Utils.Enter
|
||||
build-depends:
|
||||
base >= 4.7 && < 4.10
|
||||
, base-compat >= 0.9
|
||||
, aeson >= 0.7
|
||||
, attoparsec >= 0.12
|
||||
, bytestring == 0.10.*
|
||||
, bytestring-conversion == 0.3.*
|
||||
, case-insensitive >= 1.2
|
||||
, http-api-data >= 0.1 && < 0.3
|
||||
, http-media >= 0.4 && < 0.7
|
||||
, http-types >= 0.8 && < 0.10
|
||||
, mtl >= 2 && < 3
|
||||
, mmorph >= 1
|
||||
, text >= 1 && < 2
|
||||
, string-conversions >= 0.3 && < 0.5
|
||||
, network-uri >= 2.6
|
||||
, vault >= 0.3 && <0.4
|
||||
base >= 4.7 && < 4.10
|
||||
, base-compat >= 0.9 && < 0.10
|
||||
, aeson >= 0.7 && < 0.12
|
||||
, attoparsec >= 0.12 && < 0.14
|
||||
, bytestring >= 0.10 && < 0.11
|
||||
, bytestring-conversion >= 0.3 && < 0.4
|
||||
, case-insensitive >= 1.2 && < 1.3
|
||||
, http-api-data >= 0.1 && < 0.3
|
||||
, http-media >= 0.4 && < 0.7
|
||||
, http-types >= 0.8 && < 0.10
|
||||
, mtl >= 2.0 && < 2.3
|
||||
, mmorph >= 1 && < 1.1
|
||||
, text >= 1 && < 1.3
|
||||
, string-conversions >= 0.3 && < 0.5
|
||||
, network-uri >= 2.6 && < 2.7
|
||||
, vault >= 0.3 && < 0.4
|
||||
hs-source-dirs: src
|
||||
default-language: Haskell2010
|
||||
other-extensions: CPP
|
||||
|
|
|
@ -319,7 +319,7 @@ instance MimeRender OctetStream BS.ByteString where
|
|||
|
||||
-- | A type for responses without content-body.
|
||||
data NoContent = NoContent
|
||||
deriving (Show, Eq, Read)
|
||||
deriving (Show, Eq, Read, Generic)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
|
|
@ -10,7 +10,7 @@ import Data.Proxy
|
|||
|
||||
import Servant.API
|
||||
|
||||
type GET = Get '[JSON] ()
|
||||
type GET = Get '[JSON] NoContent
|
||||
|
||||
type ComprehensiveAPI =
|
||||
GET :<|>
|
||||
|
@ -25,10 +25,10 @@ type ComprehensiveAPI =
|
|||
-- Raw :<|>
|
||||
RemoteHost :> GET :<|>
|
||||
ReqBody '[JSON] Int :> GET :<|>
|
||||
Get '[JSON] (Headers '[Header "foo" Int] ()) :<|>
|
||||
Get '[JSON] (Headers '[Header "foo" Int] NoContent) :<|>
|
||||
"foo" :> GET :<|>
|
||||
Vault :> GET :<|>
|
||||
Verb 'POST 204 '[JSON] () :<|>
|
||||
Verb 'POST 204 '[JSON] NoContent :<|>
|
||||
Verb 'POST 204 '[JSON] Int :<|>
|
||||
WithNamedContext "foo" '[] GET
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
-- >>>
|
||||
-- >>>
|
||||
-- >>> type Hello = "hello" :> Get '[JSON] Int
|
||||
-- >>> type Bye = "bye" :> QueryParam "name" String :> Delete '[JSON] ()
|
||||
-- >>> type Bye = "bye" :> QueryParam "name" String :> Delete '[JSON] NoContent
|
||||
-- >>> type API = Hello :<|> Bye
|
||||
-- >>> let api = Proxy :: Proxy API
|
||||
--
|
||||
|
@ -47,11 +47,11 @@
|
|||
-- If the API has an endpoint with parameters then we can generate links with
|
||||
-- or without those:
|
||||
--
|
||||
-- >>> let with = Proxy :: Proxy ("bye" :> QueryParam "name" String :> Delete '[JSON] ())
|
||||
-- >>> let with = Proxy :: Proxy ("bye" :> QueryParam "name" String :> Delete '[JSON] NoContent)
|
||||
-- >>> print $ safeLink api with (Just "Hubert")
|
||||
-- bye?name=Hubert
|
||||
--
|
||||
-- >>> let without = Proxy :: Proxy ("bye" :> Delete '[JSON] ())
|
||||
-- >>> let without = Proxy :: Proxy ("bye" :> Delete '[JSON] NoContent)
|
||||
-- >>> print $ safeLink api without
|
||||
-- bye
|
||||
--
|
||||
|
@ -69,7 +69,7 @@
|
|||
-- Attempting to construct a link to an endpoint that does not exist in api
|
||||
-- will result in a type error like this:
|
||||
--
|
||||
-- >>> let bad_link = Proxy :: Proxy ("hello" :> Delete '[JSON] ())
|
||||
-- >>> let bad_link = Proxy :: Proxy ("hello" :> Delete '[JSON] NoContent)
|
||||
-- >>> safeLink api bad_link
|
||||
-- ...
|
||||
-- ...Could not deduce...
|
||||
|
|
|
@ -12,16 +12,16 @@ import Servant.API
|
|||
|
||||
type TestApi =
|
||||
-- Capture and query params
|
||||
"hello" :> Capture "name" String :> QueryParam "capital" Bool :> Delete '[JSON] ()
|
||||
"hello" :> Capture "name" String :> QueryParam "capital" Bool :> Delete '[JSON] NoContent
|
||||
|
||||
-- Flags
|
||||
:<|> "balls" :> QueryFlag "bouncy" :> QueryFlag "fast" :> Delete '[JSON] ()
|
||||
:<|> "balls" :> QueryFlag "bouncy" :> QueryFlag "fast" :> Delete '[JSON] NoContent
|
||||
|
||||
-- All of the verbs
|
||||
:<|> "get" :> Get '[JSON] ()
|
||||
:<|> "put" :> Put '[JSON] ()
|
||||
:<|> "post" :> ReqBody '[JSON] 'True :> Post '[JSON] ()
|
||||
:<|> "delete" :> Header "ponies" String :> Delete '[JSON] ()
|
||||
:<|> "get" :> Get '[JSON] NoContent
|
||||
:<|> "put" :> Put '[JSON] NoContent
|
||||
:<|> "post" :> ReqBody '[JSON] 'True :> Post '[JSON] NoContent
|
||||
:<|> "delete" :> Header "ponies" String :> Delete '[JSON] NoContent
|
||||
:<|> "raw" :> Raw
|
||||
|
||||
|
||||
|
@ -38,26 +38,26 @@ shouldBeURI link expected =
|
|||
spec :: Spec
|
||||
spec = describe "Servant.Utils.Links" $ do
|
||||
it "generates correct links for capture query params" $ do
|
||||
let l1 = Proxy :: Proxy ("hello" :> Capture "name" String :> Delete '[JSON] ())
|
||||
let l1 = Proxy :: Proxy ("hello" :> Capture "name" String :> Delete '[JSON] NoContent)
|
||||
apiLink l1 "hi" `shouldBeURI` "hello/hi"
|
||||
|
||||
let l2 = Proxy :: Proxy ("hello" :> Capture "name" String
|
||||
:> QueryParam "capital" Bool
|
||||
:> Delete '[JSON] ())
|
||||
:> Delete '[JSON] NoContent)
|
||||
apiLink l2 "bye" (Just True) `shouldBeURI` "hello/bye?capital=true"
|
||||
|
||||
|
||||
it "generates correct links for query flags" $ do
|
||||
let l1 = Proxy :: Proxy ("balls" :> QueryFlag "bouncy"
|
||||
:> QueryFlag "fast" :> Delete '[JSON] ())
|
||||
:> QueryFlag "fast" :> Delete '[JSON] NoContent)
|
||||
apiLink l1 True True `shouldBeURI` "balls?bouncy&fast"
|
||||
apiLink l1 False True `shouldBeURI` "balls?fast"
|
||||
|
||||
it "generates correct links for all of the verbs" $ do
|
||||
apiLink (Proxy :: Proxy ("get" :> Get '[JSON] ())) `shouldBeURI` "get"
|
||||
apiLink (Proxy :: Proxy ("put" :> Put '[JSON] ())) `shouldBeURI` "put"
|
||||
apiLink (Proxy :: Proxy ("post" :> Post '[JSON] ())) `shouldBeURI` "post"
|
||||
apiLink (Proxy :: Proxy ("delete" :> Delete '[JSON] ())) `shouldBeURI` "delete"
|
||||
apiLink (Proxy :: Proxy ("get" :> Get '[JSON] NoContent)) `shouldBeURI` "get"
|
||||
apiLink (Proxy :: Proxy ("put" :> Put '[JSON] NoContent)) `shouldBeURI` "put"
|
||||
apiLink (Proxy :: Proxy ("post" :> Post '[JSON] NoContent)) `shouldBeURI` "post"
|
||||
apiLink (Proxy :: Proxy ("delete" :> Delete '[JSON] NoContent)) `shouldBeURI` "delete"
|
||||
apiLink (Proxy :: Proxy ("raw" :> Raw)) `shouldBeURI` "raw"
|
||||
|
||||
|
||||
|
@ -93,9 +93,9 @@ spec = describe "Servant.Utils.Links" $ do
|
|||
-- sanity check
|
||||
-- >>> apiLink (Proxy :: Proxy AllGood)
|
||||
-- get
|
||||
type WrongPath = "getTypo" :> Get '[JSON] ()
|
||||
type WrongPath = "getTypo" :> Get '[JSON] NoContent
|
||||
type WrongReturnType = "get" :> Get '[JSON] Bool
|
||||
type WrongContentType = "get" :> Get '[OctetStream] ()
|
||||
type WrongMethod = "get" :> Post '[JSON] ()
|
||||
type WrongContentType = "get" :> Get '[OctetStream] NoContent
|
||||
type WrongMethod = "get" :> Post '[JSON] NoContent
|
||||
type NotALink = "hello" :> ReqBody '[JSON] 'True :> Get '[JSON] Bool
|
||||
type AllGood = "get" :> Get '[JSON] ()
|
||||
type AllGood = "get" :> Get '[JSON] NoContent
|
||||
|
|
Loading…
Reference in a new issue