on becc013 help sign in
.gitignore+5−5
since splitsnapshots
unifiedsplit
@@ -1,8 +1,8 @@
1−dist
1+/dist
2−bin
2+/bin
3−lib
3+/lib
4−share
4+/share
5−packages
5+/packages
6*-packages.conf.d
6*-packages.conf.d
7cabal-dev
7cabal-dev
8add-source-timestamps
8add-source-timestamps
scripts/bump-versions.sh+8−21
@@ -16,33 +16,17 @@
16set -o nounset
16set -o nounset
17set -o errexit
17set -o errexit
18
18
19−DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
19+DIR=$( dirname $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ))
20−DRY_RUN=false
20+. "${DIR}/scripts/lib/common.sh"
21−POSITION="none"
22−SOURCES_TXT="$( dirname $DIR)/sources.txt"
23−
24−declare -a SOURCES
25−readarray -t SOURCES < "$SOURCES_TXT"
26
21
27usage () {
22usage () {
28− echo " bump-versions <POSITION> [-d|--dry-run]"
23+ echo " bump-versions.sh <POSITION> [-d|--dry-run]"
29 echo " | [-h|--help]"
24 echo " | [-h|--help]"
30 echo " Bumps the specified positional version of all servant packages."
25 echo " Bumps the specified positional version of all servant packages."
31 echo " POSITION is a number between 0 and 3, inclusive."
26 echo " POSITION is a number between 0 and 3, inclusive."
32 exit 0
27 exit 0
33}
28}
34
29
35−join () { local IFS="$1"; shift; echo "$*"; }
36−
37−versions_equal () {
38− local NUM=$(find . -name 'servant*.cabal' | xargs grep "^version:" | awk '{ print $2 }' | uniq -c | wc -l)
39− if [ 1 -eq $NUM ] ; then
40− return 0
41− else
42− echo "versions of packages are not all the same!" && exit 1
43− fi
44−}
45−
46if [ $# -eq 0 ] ; then
30if [ $# -eq 0 ] ; then
47 echo "expecting one or more arguments. Got 0"
31 echo "expecting one or more arguments. Got 0"
48 usage
32 usage
@@ -71,8 +55,11 @@ while [ "${1:-unset}" != "unset" ] ; do
71done
55done
72
56
73if $DRY_RUN ; then
57if $DRY_RUN ; then
58+ echo "Would have bumped position ${POSITION} on these packages:"
74− bumper --dry-run -"$POSITION" $(join , "${SOURCES[@]}")
59+ ( cd "$ROOT" && bumper --dry-run -"$POSITION" $(join , "${SOURCES[@]}") )
75else
60else
76− bumper -"$POSITION" $(join , "${SOURCES[@]}")
61+ ( cd "$ROOT" && bumper -"$POSITION" $(join , "${SOURCES[@]}") )
77fi
62fi
78
63
64+# Trailing newline, bumper does not ship with its own.
65+echo
scripts/lib/common.shnew file+32
@@ -0,0 +1,32 @@
1+#!/bin/bash -
2+#===============================================================================
3+#
4+# FILE: lib/common.sh
5+#
6+# DESCRIPTION: Common functions for servant's shell scripts
7+# Meant to be sourced rather than run.
8+#
9+# REQUIREMENTS: bash >= 4
10+#===============================================================================
11+
12+
13+DIR=$( dirname $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ))
14+ROOT=$( dirname $DIR )
15+DRY_RUN=false
16+POSITION="none"
17+SOURCES_TXT="$( dirname $DIR)/sources.txt"
18+CABAL=${CABAL:-cabal}
19+
20+declare -a SOURCES
21+readarray -t SOURCES < "$SOURCES_TXT"
22+
23+join () { local IFS="$1"; shift; echo "$*"; }
24+
25+versions_equal () {
26+ local NUM=$(cd "$ROOT" && find . -name 'servant*.cabal' | xargs grep "^version:" | awk '{ print $2 }' | uniq -c | wc -l)
27+ if [ 1 -eq $NUM ] ; then
28+ return 0
29+ else
30+ echo "versions of packages are not all the same!" && exit 1
31+ fi
32+}
scripts/start-sandbox.sh+1−5
@@ -14,11 +14,7 @@ set -o nounset
14set -o errexit
14set -o errexit
15
15
16DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
16DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
17−SOURCES_TXT="$( dirname $DIR)/sources.txt"
17+. "$DIR"/lib/common.sh
18−CABAL=${CABAL:-cabal}
19−
20−declare -a SOURCES
21−readarray -t SOURCES < "$SOURCES_TXT"
22
18
23prepare_sandbox () {
19prepare_sandbox () {
24 $CABAL sandbox init
20 $CABAL sandbox init
scripts/test-all.sh+3−6
@@ -15,13 +15,10 @@ set -o nounset
15set -o errexit
15set -o errexit
16
16
17DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
17DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
18−GHC_FLAGS="-Werror"
18+. "$DIR"/lib/common.sh
19−SOURCES_TXT="$( dirname $DIR)/sources.txt"
20−CABAL=${CABAL:-cabal}
21−
22−declare -a SOURCES
23−readarray -t SOURCES < "$SOURCES_TXT"
24
19
20+# TODO: Remove missing-methods after https://github.com/bos/aeson/issues/290
21+GHC_FLAGS="-Werror -fno-warn-missing-methods"
25
22
26prepare_sandbox () {
23prepare_sandbox () {
27 $CABAL sandbox init
24 $CABAL sandbox init
scripts/update-defaults-nix.sh+1−5
@@ -12,11 +12,7 @@ set -o nounset
12set -o errexit
12set -o errexit
13
13
14DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
14DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
15−BASE_DIR="$( dirname $DIR)"
15+. "$DIR"/lib/common.sh
16−SOURCES_TXT="$BASE_DIR/sources.txt"
17−
18−declare -a SOURCES
19−readarray -t SOURCES < "$SOURCES_TXT"
20
16
21for s in ${SOURCES[@]} ; do
17for s in ${SOURCES[@]} ; do
22 echo $s
18 echo $s
scripts/upload.shnew file+52
@@ -0,0 +1,52 @@
1+#!/bin/bash -
2+#===============================================================================
3+#
4+# FILE: upload.sh
5+#
6+# USAGE: ./upload.sh <USER> <PASSWORD>
7+#
8+# DESCRIPTION: Uploads all servant packages to Hackage
9+#
10+# REQUIREMENTS: cabal, bash >= 4
11+# AUTHOR: Julian K. Arni
12+# CREATED: 05.06.2015 13:05
13+#===============================================================================
14+
15+set -o nounset
16+set -o errexit
17+
18+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
19+. "$DIR"/lib/common.sh
20+
21+usage () {
22+ echo " upload.sh <USER> <PASSWORD>"
23+ echo " Uploads all servant packages to Hackage"
24+ exit 0
25+}
26+
27+
28+upload_package () {
29+ local package="$1"
30+ local user="$2"
31+ local pass="$3"
32+ local cabalFile="$package.cabal"
33+ pushd "$package"
34+ local version=$(grep -i '^version:' $cabalFile | awk '{ print $2 }')
35+ local sdist="dist/${package}-${version}.tar.gz"
36+ cabal sdist
37+ echo "User is: $user"
38+ cabal upload --user="$user" --password="$pass" "$sdist"
39+ popd
40+}
41+
42+
43+if [ $# -ne 2 ] ; then
44+ echo "expecting two arguments."
45+ usage
46+fi
47+
48+versions_equal
49+
50+for s in ${SOURCES[@]} ; do
51+ upload_package "$s" "$1" "$2"
52+done
servant-blaze/servant-blaze.cabal+5−1
@@ -2,7 +2,7 @@
2-- documentation, see http://haskell.org/cabal/users-guide/
2-- documentation, see http://haskell.org/cabal/users-guide/
3
3
4name: servant-blaze
4name: servant-blaze
5−version: 0.4.1
5+version: 0.4.4.6
6synopsis: Blaze-html support for servant
6synopsis: Blaze-html support for servant
7-- description:
7-- description:
8homepage: http://haskell-servant.github.io/
8homepage: http://haskell-servant.github.io/
@@ -15,6 +15,10 @@ category: Web
15build-type: Simple
15build-type: Simple
16-- extra-source-files:
16-- extra-source-files:
17cabal-version: >=1.10
17cabal-version: >=1.10
18+bug-reports: http://github.com/haskell-servant/servant/issues
19+source-repository head
20+ type: git
21+ location: http://github.com/haskell-servant/servant.git
18
22
19library
23library
20 exposed-modules: Servant.HTML.Blaze
24 exposed-modules: Servant.HTML.Blaze
servant-cassava/LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright (c) 2015, Julian K. Arni
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+
11+ * Redistributions in binary form must reproduce the above
12+ copyright notice, this list of conditions and the following
13+ disclaimer in the documentation and/or other materials provided
14+ with the distribution.
15+
16+ * Neither the name of Julian K. Arni nor the names of other
17+ contributors may be used to endorse or promote products derived
18+ from this software without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
servant-cassava/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
servant-cassava/servant-cassava.cabalnew file+29
@@ -0,0 +1,29 @@
1+-- Initial servant-cassava.cabal generated by cabal init. For further
2+-- documentation, see http://haskell.org/cabal/users-guide/
3+
4+name: servant-cassava
5+version: 0.4.4.6
6+synopsis: Servant CSV content-type for cassava
7+-- description:
8+homepage: http://haskell-servant.github.io/
9+license: BSD3
10+license-file: LICENSE
11+author: Julian K. Arni
12+maintainer: jkarni@gmail.com
13+-- copyright:
14+-- category:
15+build-type: Simple
16+-- extra-source-files:
17+cabal-version: >=1.10
18+
19+library
20+ exposed-modules: Servant.CSV.Cassava
21+ -- other-modules:
22+ -- other-extensions:
23+ build-depends: base >=4.6 && <5
24+ , cassava >0.4 && <0.5
25+ , servant == 0.4.*
26+ , http-media
27+ , vector
28+ hs-source-dirs: src
29+ default-language: Haskell2010
servant-cassava/src/Servant/CSV/Cassava.hsnew file+88
@@ -0,0 +1,88 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
7+
8+-- | A @CSV@ empty datatype with `MimeRender` and `MimeUnrender` instances for
9+-- @cassava@'s encoding and decoding classes.
10+--
11+-- >>> type Eg = Get '[(CSV', MyEncodeOptions)] [(Int, String)]
12+--
13+-- Default encoding and decoding options are also provided, along with the
14+-- @CSV@ type synonym that uses them.
15+--
16+-- >>> type EgDefault = Get '[CSV] [(Int, String)]
17+module Servant.CSV.Cassava where
18+
19+import Data.Csv
20+import Data.Proxy (Proxy (..))
21+import Data.Typeable (Typeable)
22+import Data.Vector (Vector)
23+import GHC.Generics (Generic)
24+import qualified Network.HTTP.Media as M
25+import Servant.API (Accept (..), MimeRender (..),
26+ MimeUnrender (..))
27+
28+data CSV' deriving (Typeable, Generic)
29+
30+type CSV = (CSV', DefaultDecodeOpts)
31+
32+-- | @text/csv;charset=utf-8@
33+instance Accept (CSV', a) where
34+ contentType _ = "text" M.// "csv" M./: ("charset", "utf-8")
35+
36+-- * Encoding
37+
38+-- ** Instances
39+
40+-- | Encode with 'encodeByNameWith'. The 'Header' param is used for determining
41+-- the order of headers and fields.
42+instance ( ToNamedRecord a, EncodeOpts opt
43+ ) => MimeRender (CSV', opt) (Header, [a]) where
44+ mimeRender _ (hdr, vals) = encodeByNameWith (encodeOpts p) hdr vals
45+ where p = Proxy :: Proxy opt
46+
47+-- | Encode with 'encodeDefaultOrderedByNameWith'
48+instance ( DefaultOrdered a, ToNamedRecord a, EncodeOpts opt
49+ ) => MimeRender (CSV', opt) [a] where
50+ mimeRender _ = encodeDefaultOrderedByNameWith (encodeOpts p)
51+ where p = Proxy :: Proxy opt
52+
53+
54+-- ** Encode Options
55+
56+class EncodeOpts a where
57+ encodeOpts :: Proxy a -> EncodeOptions
58+
59+data DefaultEncodeOpts deriving (Typeable, Generic)
60+
61+instance EncodeOpts DefaultEncodeOpts where
62+ encodeOpts _ = defaultEncodeOptions
63+
64+-- * Decoding
65+
66+-- ** Instances
67+
68+-- | Decode with 'decodeByNameWith'
69+instance ( FromNamedRecord a, DecodeOpts opt
70+ ) => MimeUnrender (CSV', opt) (Header, Vector a) where
71+ mimeUnrender _ = decodeByNameWith (decodeOpts p)
72+ where p = Proxy :: Proxy opt
73+
74+-- | Decode with 'decodeWith'. Assumes data has headers, which are stripped.
75+instance ( FromRecord a, DecodeOpts opt
76+ ) => MimeUnrender (CSV', opt) (Vector a) where
77+ mimeUnrender _ = decodeWith (decodeOpts p) HasHeader
78+ where p = Proxy :: Proxy opt
79+
80+-- ** Decode Options
81+
82+class DecodeOpts a where
83+ decodeOpts :: Proxy a -> DecodeOptions
84+
85+data DefaultDecodeOpts deriving (Typeable, Generic)
86+
87+instance DecodeOpts DefaultDecodeOpts where
88+ decodeOpts _ = defaultDecodeOptions
servant-client/servant-client.cabal+1−1
@@ -1,5 +1,5 @@
1name: servant-client
1name: servant-client
2−version: 0.4.1
2+version: 0.4.4.6
3synopsis: automatical derivation of querying functions for servant webservices
3synopsis: automatical derivation of querying functions for servant webservices
4description:
4description:
5 This library lets you derive automatically Haskell functions that
5 This library lets you derive automatically Haskell functions that
servant-client/src/Servant/Client.hs+2−2
@@ -252,7 +252,7 @@ instance
252 (MimeUnrender ct a) => HasClient (Post (ct ': cts) a) where
252 (MimeUnrender ct a) => HasClient (Post (ct ': cts) a) where
253 type Client (Post (ct ': cts) a) = EitherT ServantError IO a
253 type Client (Post (ct ': cts) a) = EitherT ServantError IO a
254 clientWithRoute Proxy req baseurl =
254 clientWithRoute Proxy req baseurl =
255− snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPost req [200,201] baseurl
255+ snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPost req [200, 201, 202] baseurl
256
256
257-- | If you have a 'Post xs ()' endpoint, the client expects a 204 No Content
257-- | If you have a 'Post xs ()' endpoint, the client expects a 204 No Content
258-- HTTP header.
258-- HTTP header.
@@ -275,7 +275,7 @@ instance
275 ) => HasClient (Post (ct ': cts) (Headers ls a)) where
275 ) => HasClient (Post (ct ': cts) (Headers ls a)) where
276 type Client (Post (ct ': cts) (Headers ls a)) = EitherT ServantError IO (Headers ls a)
276 type Client (Post (ct ': cts) (Headers ls a)) = EitherT ServantError IO (Headers ls a)
277 clientWithRoute Proxy req baseurl = do
277 clientWithRoute Proxy req baseurl = do
278− (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPost req [200, 201] baseurl
278+ (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPost req [200, 201, 202] baseurl
279 return $ Headers { getResponse = resp
279 return $ Headers { getResponse = resp
280 , getHeadersHList = buildHeadersTo hdrs
280 , getHeadersHList = buildHeadersTo hdrs
281 }
281 }
servant-docs/CHANGELOG.md+4
@@ -1,3 +1,7 @@
1+0.4.3
2+-----
3+* docsWith will no longer eat your documentation (https://github.com/haskell-servant/servant/pull/124)
4+
10.4
50.4
2---
6---
3* `Delete` now is like `Get`, `Post`, `Put`, and `Patch` and returns a response body
7* `Delete` now is like `Get`, `Post`, `Put`, and `Patch` and returns a response body
servant-docs/servant-docs.cabal+2−1
@@ -1,5 +1,5 @@
1name: servant-docs
1name: servant-docs
2−version: 0.4.1
2+version: 0.4.4.6
3synopsis: generate API docs for your servant webservice
3synopsis: generate API docs for your servant webservice
4description:
4description:
5 Library for generating API docs from a servant API definition.
5 Library for generating API docs from a servant API definition.
@@ -70,6 +70,7 @@ test-suite spec
70 base
70 base
71 , aeson
71 , aeson
72 , hspec
72 , hspec
73+ , lens
73 , servant
74 , servant
74 , servant-docs
75 , servant-docs
75 , string-conversions
76 , string-conversions
servant-docs/src/Servant/Docs/Internal.hs+8−6
@@ -22,18 +22,20 @@ module Servant.Docs.Internal where
22#if !MIN_VERSION_base(4,8,0)
22#if !MIN_VERSION_base(4,8,0)
23import Control.Applicative
23import Control.Applicative
24#endif
24#endif
25−import Control.Lens
25+import Control.Lens (makeLenses, over, traversed, (%~),
26+ (&), (.~), (<>~), (^.), _1, _2,
27+ _last, (|>))
28+import Data.ByteString.Conversion (ToByteString, toByteString)
26import Data.ByteString.Lazy.Char8 (ByteString)
29import Data.ByteString.Lazy.Char8 (ByteString)
27import qualified Data.CaseInsensitive as CI
30import qualified Data.CaseInsensitive as CI
28−import Data.Hashable
31+import Data.Hashable (Hashable)
29import Data.HashMap.Strict (HashMap)
32import Data.HashMap.Strict (HashMap)
30import Data.List
33import Data.List
31import Data.Maybe
34import Data.Maybe
32import Data.Monoid
35import Data.Monoid
33import Data.Ord (comparing)
36import Data.Ord (comparing)
34−import Data.Proxy
37+import Data.Proxy (Proxy(Proxy))
35−import Data.ByteString.Conversion (ToByteString, toByteString)
36−import Data.String.Conversions
38+import Data.String.Conversions (cs)
37import Data.Text (Text, pack, unpack)
39import Data.Text (Text, pack, unpack)
38import GHC.Exts (Constraint)
40import GHC.Exts (Constraint)
39import GHC.Generics
41import GHC.Generics
@@ -338,7 +340,7 @@ extraInfo p action =
338docsWith :: HasDocs layout => [DocIntro] -> ExtraInfo layout -> Proxy layout -> API
340docsWith :: HasDocs layout => [DocIntro] -> ExtraInfo layout -> Proxy layout -> API
339docsWith intros (ExtraInfo endpoints) p =
341docsWith intros (ExtraInfo endpoints) p =
340 docs p & apiIntros <>~ intros
342 docs p & apiIntros <>~ intros
341− & apiEndpoints %~ HM.unionWith combineAction endpoints
343+ & apiEndpoints %~ HM.unionWith (flip combineAction) endpoints
342
344
343
345
344-- | Generate the docs for a given API that implements 'HasDocs' with with any
346-- | Generate the docs for a given API that implements 'HasDocs' with with any
servant-docs/test/Servant/DocsSpec.hs+26−3
@@ -7,7 +7,9 @@
7{-# OPTIONS_GHC -fno-warn-orphans #-}
7{-# OPTIONS_GHC -fno-warn-orphans #-}
8module Servant.DocsSpec where
8module Servant.DocsSpec where
9
9
10+import Control.Lens
10import Data.Aeson
11import Data.Aeson
12+import Data.Monoid
11import Data.Proxy
13import Data.Proxy
12import Data.String.Conversions (cs)
14import Data.String.Conversions (cs)
13import GHC.Generics
15import GHC.Generics
@@ -21,7 +23,27 @@ spec = describe "Servant.Docs" $ do
21
23
22 describe "markdown" $ do
24 describe "markdown" $ do
23 let md = markdown (docs (Proxy :: Proxy TestApi1))
25 let md = markdown (docs (Proxy :: Proxy TestApi1))
24−
26+ tests md
27+
28+ describe "markdown with extra info" $ do
29+ let
30+ extra = extraInfo
31+ (Proxy :: Proxy (Get '[JSON, PlainText] Int))
32+ (defAction & notes <>~ [DocNote "Get an Integer" ["get an integer in Json or plain text"]])
33+ <>
34+ extraInfo
35+ (Proxy :: Proxy (ReqBody '[JSON] String :> Post '[JSON] Datatype1))
36+ (defAction & notes <>~ [DocNote "Post data" ["Posts some Json data"]])
37+ md = markdown (docsWith [] extra (Proxy :: Proxy TestApi1))
38+ tests md
39+ it "contains the extra info provided" $ do
40+ md `shouldContain` "Get an Integer"
41+ md `shouldContain` "Post data"
42+ md `shouldContain` "get an integer in Json or plain text"
43+ md `shouldContain` "Posts some Json data"
44+
45+ where
46+ tests md = do
25 it "mentions supported content-types" $ do
47 it "mentions supported content-types" $ do
26 md `shouldContain` "application/json"
48 md `shouldContain` "application/json"
27 md `shouldContain` "text/plain;charset=utf-8"
49 md `shouldContain` "text/plain;charset=utf-8"
@@ -34,10 +56,11 @@ spec = describe "Servant.Docs" $ do
34 md `shouldContain` "POST"
56 md `shouldContain` "POST"
35 md `shouldContain` "GET"
57 md `shouldContain` "GET"
36
58
37− it "contains response samples" $ do
59+ it "contains response samples" $
38 md `shouldContain` "{\"dt1field1\":\"field 1\",\"dt1field2\":13}"
60 md `shouldContain` "{\"dt1field1\":\"field 1\",\"dt1field2\":13}"
39− it "contains request body samples" $ do
61+ it "contains request body samples" $
40 md `shouldContain` "17"
62 md `shouldContain` "17"
63+
41-- * APIs
64-- * APIs
42
65
43data Datatype1 = Datatype1 { dt1field1 :: String
66data Datatype1 = Datatype1 { dt1field1 :: String
servant-examples/CHANGELOG.mdnew file+3
@@ -0,0 +1,3 @@
1+0.4.3
2+-----
3+* Clarify some variable names in the examples + semantic html pedantry
servant-examples/auth-combinator/auth-combinator.hs+1
@@ -5,6 +5,7 @@
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8+{-# OPTIONS_GHC -fno-warn-unused-binds #-}
8import Data.Aeson
9import Data.Aeson
9import Data.ByteString (ByteString)
10import Data.ByteString (ByteString)
10import Data.Text (Text)
11import Data.Text (Text)
servant-examples/hackage/hackage.hs+2
@@ -2,6 +2,8 @@
2{-# LANGUAGE DeriveGeneric #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE TypeOperators #-}
3{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
5+{-# OPTIONS_GHC -fno-warn-unused-binds #-}
6+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
5import Control.Applicative
7import Control.Applicative
6import Control.Monad
8import Control.Monad
7import Control.Monad.IO.Class
9import Control.Monad.IO.Class
servant-examples/servant-examples.cabal+7−2
@@ -1,5 +1,5 @@
1name: servant-examples
1name: servant-examples
2−version: 0.4.1
2+version: 0.4.4.6
3synopsis: Example programs for servant
3synopsis: Example programs for servant
4description: Example programs for servant,
4description: Example programs for servant,
5 showcasing solutions to common needs.
5 showcasing solutions to common needs.
@@ -12,12 +12,16 @@ maintainer: alpmestan@gmail.com
12category: Web
12category: Web
13build-type: Simple
13build-type: Simple
14cabal-version: >=1.10
14cabal-version: >=1.10
15+bug-reports: http://github.com/haskell-servant/servant/issues
16+source-repository head
17+ type: git
18+ location: http://github.com/haskell-servant/servant.git
15
19
16executable tutorial
20executable tutorial
17 main-is: tutorial.hs
21 main-is: tutorial.hs
18 other-modules: T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
22 other-modules: T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
19 build-depends:
23 build-depends:
20− aeson >= 0.8
24+ aeson >= 0.10
21 , base >= 4.7 && < 5
25 , base >= 4.7 && < 5
22 , bytestring
26 , bytestring
23 , directory
27 , directory
@@ -41,6 +45,7 @@ executable tutorial
41
45
42executable t8-main
46executable t8-main
43 main-is: t8-main.hs
47 main-is: t8-main.hs
48+ other-modules: T3, T8
44 hs-source-dirs: tutorial
49 hs-source-dirs: tutorial
45 default-language: Haskell2010
50 default-language: Haskell2010
46 build-depends:
51 build-depends:
servant-examples/tutorial/T1.hs+1−6
@@ -17,17 +17,12 @@ data User = User
17 , registration_date :: Day
17 , registration_date :: Day
18 } deriving (Eq, Show, Generic)
18 } deriving (Eq, Show, Generic)
19
19
20−-- orphan ToJSON instance for Day. necessary to derive one for User
21−instance ToJSON Day where
22− -- display a day in YYYY-mm-dd format
23− toJSON d = toJSON (showGregorian d)
24−
25instance ToJSON User
20instance ToJSON User
26
21
27type UserAPI = "users" :> Get '[JSON] [User]
22type UserAPI = "users" :> Get '[JSON] [User]
28
23
29users :: [User]
24users :: [User]
30−users =
25+users =
31 [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
26 [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
32 , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
27 , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
33 ]
28 ]
servant-examples/tutorial/T10.hs+1
@@ -4,6 +4,7 @@
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# OPTIONS_GHC -fno-warn-orphans #-}
7module T10 where
8module T10 where
8
9
9import Data.ByteString.Lazy (ByteString)
10import Data.ByteString.Lazy (ByteString)
servant-examples/tutorial/T2.hs−5
@@ -17,11 +17,6 @@ data User = User
17 , registration_date :: Day
17 , registration_date :: Day
18 } deriving (Eq, Show, Generic)
18 } deriving (Eq, Show, Generic)
19
19
20−-- orphan ToJSON instance for Day. necessary to derive one for User
21−instance ToJSON Day where
22− -- display a day in YYYY-mm-dd format
23− toJSON d = toJSON (showGregorian d)
24−
25instance ToJSON User
20instance ToJSON User
26
21
27type UserAPI = "users" :> Get '[JSON] [User]
22type UserAPI = "users" :> Get '[JSON] [User]
servant-examples/tutorial/T3.hs+1−1
@@ -70,7 +70,7 @@ server = position
70 :<|> marketing
70 :<|> marketing
71
71
72 where position :: Int -> Int -> EitherT ServantErr IO Position
72 where position :: Int -> Int -> EitherT ServantErr IO Position
73− position x y = return (Position x y)
73+ position a b = return (Position a b)
74
74
75 hello :: Maybe String -> EitherT ServantErr IO HelloMessage
75 hello :: Maybe String -> EitherT ServantErr IO HelloMessage
76 hello mname = return . HelloMessage $ case mname of
76 hello mname = return . HelloMessage $ case mname of
servant-examples/tutorial/T4.hs+10−9
@@ -4,6 +4,7 @@
4{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE OverloadedStrings #-}
7+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
7module T4 where
8module T4 where
8
9
9import Data.Aeson
10import Data.Aeson
@@ -25,23 +26,23 @@ instance ToJSON Person
25
26
26-- HTML serialization of a single person
27-- HTML serialization of a single person
27instance ToHtml Person where
28instance ToHtml Person where
28− toHtml p =
29+ toHtml person =
29 tr_ $ do
30 tr_ $ do
30− td_ (toHtml $ firstName p)
31+ td_ (toHtml $ firstName person)
31− td_ (toHtml $ lastName p)
32+ td_ (toHtml $ lastName person)
32− td_ (toHtml . show $ age p)
33+ td_ (toHtml . show $ age person)
33
34
34 toHtmlRaw = toHtml
35 toHtmlRaw = toHtml
35
36
36-- HTML serialization of a list of persons
37-- HTML serialization of a list of persons
37instance ToHtml [Person] where
38instance ToHtml [Person] where
38− toHtml persons = table_ $ do
39+ toHtml ps = table_ $ do
39 tr_ $ do
40 tr_ $ do
40− td_ "first name"
41+ th_ "first name"
41− td_ "last name"
42+ th_ "last name"
42− td_ "age"
43+ th_ "age"
43
44
44− foldMap toHtml persons
45+ foldMap toHtml ps
45
46
46 toHtmlRaw = toHtml
47 toHtmlRaw = toHtml
47
48
servant-examples/tutorial/T8.hs+1−1
@@ -1,10 +1,10 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE TypeFamilies #-}
3{-# LANGUAGE TypeOperators #-}
3{-# LANGUAGE TypeOperators #-}
4+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
4module T8 where
5module T8 where
5
6
6import Control.Monad.Trans.Either
7import Control.Monad.Trans.Either
7−import Data.Aeson
8import Servant
8import Servant
9import Servant.Client
9import Servant.Client
10
10
servant-examples/tutorial/T9.hs+1
@@ -3,6 +3,7 @@
3{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE DeriveGeneric #-}
4{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE OverloadedStrings #-}
6+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
6module T9 where
7module T9 where
7
8
8import Control.Applicative
9import Control.Applicative
servant-examples/wai-middleware/wai-middleware.hs+1
@@ -1,6 +1,7 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DeriveGeneric #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
4+{-# OPTIONS_GHC -fno-warn-unused-binds #-}
4import Data.Aeson
5import Data.Aeson
5import Data.Text
6import Data.Text
6import GHC.Generics
7import GHC.Generics
servant-jquery/CHANGELOG.md+4
@@ -1,3 +1,7 @@
1+0.4.3
2+-----
3+* Content type now set to JSON when a request body is sent (#122)
4+
10.4
50.4
2---
6---
3* `Delete` now is like `Get`, `Post`, `Put`, and `Patch` and returns a response body
7* `Delete` now is like `Get`, `Post`, `Put`, and `Patch` and returns a response body
servant-jquery/servant-jquery.cabal+1−1
@@ -1,5 +1,5 @@
1name: servant-jquery
1name: servant-jquery
2−version: 0.4.1
2+version: 0.4.4.6
3synopsis: Automatically derive (jquery) javascript functions to query servant webservices
3synopsis: Automatically derive (jquery) javascript functions to query servant webservices
4description:
4description:
5 Automatically derive jquery-based javascript functions to query servant webservices.
5 Automatically derive jquery-based javascript functions to query servant webservices.
servant-jquery/src/Servant/JQuery.hs+3−2
@@ -65,13 +65,14 @@ generateJS req = "\n" <>
65
65
66 dataBody =
66 dataBody =
67 if req ^. reqBody
67 if req ^. reqBody
68− then "\n , data: JSON.stringify(body)\n"
68+ then " , data: JSON.stringify(body)\n" <>
69+ " , contentType: 'application/json'\n"
69 else ""
70 else ""
70
71
71 reqheaders =
72 reqheaders =
72 if null hs
73 if null hs
73 then ""
74 then ""
74− else "\n , headers: { " ++ headersStr ++ " }\n"
75+ else " , headers: { " ++ headersStr ++ " }\n"
75
76
76 where headersStr = intercalate ", " $ map headerStr hs
77 where headersStr = intercalate ", " $ map headerStr hs
77 headerStr header = "\"" ++
78 headerStr header = "\"" ++
servant-jquery/src/Servant/JQuery/Internal.hs+12−11
@@ -11,19 +11,20 @@
11module Servant.JQuery.Internal where
11module Servant.JQuery.Internal where
12
12
13#if !MIN_VERSION_base(4,8,0)
13#if !MIN_VERSION_base(4,8,0)
14−import Control.Applicative
14+import Control.Applicative
15#endif
15#endif
16−import Control.Lens
16+import Control.Lens (makeLenses, (%~), (&), (.~)
17+ , (<>~), (^.), _last)
17−import Data.Char (toLower)
18+import Data.Char (toLower)
18−import qualified Data.CharSet as Set
19+import qualified Data.CharSet as Set
19import qualified Data.CharSet.Unicode.Category as Set
20import qualified Data.CharSet.Unicode.Category as Set
20−import Data.List
21+import Data.List
21−import Data.Monoid
22+import Data.Monoid
22−import Data.Proxy
23+import Data.Proxy
23−import qualified Data.Text as T
24+import qualified Data.Text as T
24−import GHC.Exts (Constraint)
25+import GHC.Exts (Constraint)
25−import GHC.TypeLits
26+import GHC.TypeLits
26−import Servant.API
27+import Servant.API
27
28
28type Arg = String
29type Arg = String
29
30
servant-lucid/servant-lucid.cabal+5−1
@@ -2,7 +2,7 @@
2-- documentation, see http://haskell.org/cabal/users-guide/
2-- documentation, see http://haskell.org/cabal/users-guide/
3
3
4name: servant-lucid
4name: servant-lucid
5−version: 0.4.1
5+version: 0.4.4.6
6synopsis: Servant support for lucid
6synopsis: Servant support for lucid
7-- description:
7-- description:
8homepage: http://haskell-servant.github.io/
8homepage: http://haskell-servant.github.io/
@@ -15,6 +15,10 @@ category: Web
15build-type: Simple
15build-type: Simple
16-- extra-source-files:
16-- extra-source-files:
17cabal-version: >=1.10
17cabal-version: >=1.10
18+bug-reports: http://github.com/haskell-servant/servant/issues
19+source-repository head
20+ type: git
21+ location: http://github.com/haskell-servant/servant.git
18
22
19library
23library
20 exposed-modules: Servant.HTML.Lucid
24 exposed-modules: Servant.HTML.Lucid
servant-mock/LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright (c) 2015, Alp Mestanogullari
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+
11+ * Redistributions in binary form must reproduce the above
12+ copyright notice, this list of conditions and the following
13+ disclaimer in the documentation and/or other materials provided
14+ with the distribution.
15+
16+ * Neither the name of Alp Mestanogullari nor the names of other
17+ contributors may be used to endorse or promote products derived
18+ from this software without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
servant-mock/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
servant-mock/default.nixnew file+17
@@ -0,0 +1,17 @@
1+{ mkDerivation, aeson, base, bytestring, http-types, QuickCheck
2+, servant, servant-server, stdenv, transformers, wai, warp
3+}:
4+mkDerivation {
5+ pname = "servant-mock";
6+ version = "0.5";
7+ src = ./.;
8+ isLibrary = true;
9+ isExecutable = true;
10+ buildDepends = [
11+ aeson base bytestring http-types QuickCheck servant servant-server
12+ transformers wai warp
13+ ];
14+ homepage = "http://github.com/haskell-servant/servant";
15+ description = "Derive a mock server for free from your servant API types";
16+ license = stdenv.lib.licenses.bsd3;
17+}
servant-mock/example/main.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE TypeOperators #-}
5+import Data.Aeson
6+import GHC.Generics
7+import Network.Wai.Handler.Warp
8+import Servant
9+import Servant.Mock
10+import Test.QuickCheck.Arbitrary
11+
12+newtype User = User { username :: String }
13+ deriving (Eq, Show, Arbitrary, Generic)
14+
15+instance ToJSON User
16+
17+type API = "user" :> Get '[JSON] User
18+
19+api :: Proxy API
20+api = Proxy
21+
22+main :: IO ()
23+main = run 8080 (serve api $ mock api)
servant-mock/servant-mock.cabalnew file+46
@@ -0,0 +1,46 @@
1+name: servant-mock
2+version: 0.4.4.6
3+synopsis: Derive a mock server for free from your servant API types
4+description:
5+ Derive a mock server for free from your servant API types
6+ .
7+ See the @Servant.Mock@ module for the documentation and an example.
8+homepage: http://github.com/haskell-servant/servant
9+license: BSD3
10+license-file: LICENSE
11+author: Alp Mestanogullari
12+maintainer: alpmestan@gmail.com
13+copyright: 2015 Alp Mestanogullari
14+category: Web
15+build-type: Simple
16+cabal-version: >=1.10
17+
18+flag example
19+ description: Build the example too
20+ manual: True
21+ default: False
22+
23+library
24+ exposed-modules:
25+ Servant.Mock
26+ build-depends:
27+ base >=4.7 && <5,
28+ bytestring >= 0.10 && <0.11,
29+ http-types >= 0.8 && <0.10,
30+ servant >= 0.4,
31+ servant-server >= 0.4,
32+ transformers >= 0.3 && <0.5,
33+ QuickCheck >= 2.8 && <2.9,
34+ wai >= 3.0 && <3.3
35+ hs-source-dirs: src
36+ default-language: Haskell2010
37+
38+executable mock-app
39+ main-is: main.hs
40+ hs-source-dirs: example
41+ default-language: Haskell2010
42+ build-depends: aeson, base, servant-mock, servant-server, QuickCheck, warp
43+ if flag(example)
44+ buildable: True
45+ else
46+ buildable: False
servant-mock/shell.nixnew file+18
@@ -0,0 +1,18 @@
1+let
2+ pkgs = import <nixpkgs> {};
3+
4+ haskellPackages = pkgs.haskellPackages.override {
5+ overrides = self: super: {
6+ servant = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant {}) "--ghc-options=-Werror");
7+ servant-client = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-client {}) "--ghc-options=-Werror");
8+ servant-docs = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-docs {}) "--ghc-options=-Werror");
9+ servant-js = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-js {}) "--ghc-options=-Werror");
10+ servant-server = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-server {}) "--ghc-options=-Werror");
11+ servant-examples = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-examples {}) "--ghc-options=-Werror");
12+ servant-blaze = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-blaze {}) "--ghc-options=-Werror");
13+ servant-lucid = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.appendConfigureFlag (self.callPackage ../servant-lucid {}) "--ghc-options=-Werror");
14+ servant-mock = pkgs.haskell.lib.appendConfigureFlag (self.callPackage ./. {}) "--ghc-options=-Werror";
15+ };
16+ };
17+
18+in haskellPackages.servant-mock.env
servant-mock/src/Servant/Mock.hsnew file+178
@@ -0,0 +1,178 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE TypeFamilies #-}
7+{-# LANGUAGE TypeOperators #-}
8+{-# OPTIONS_GHC -fno-warn-orphans #-}
9+-- |
10+-- Module : Servant.Mock
11+-- Copyright : 2015 Alp Mestanogullari
12+-- License : BSD3
13+--
14+-- Maintainer : Alp Mestanogullari <alpmestan@gmail.com>
15+-- Stability : experimental
16+-- Portability : portable
17+--
18+-- Automatically derive a mock webserver that implements some API type,
19+-- just from the said API type's definition.
20+--
21+-- Using this module couldn't be simpler. Given some API type, like:
22+--
23+-- > type API = "user" :> Get '[JSON] User
24+--
25+-- that describes your web application, all you have to do is define
26+-- a 'Proxy' to it:
27+--
28+-- > myAPI :: Proxy API
29+-- > myAPI = Proxy
30+--
31+-- and call 'mock', which has the following type:
32+--
33+-- @
34+-- 'mock' :: 'HasMock' api => 'Proxy' api -> 'Server' api
35+-- @
36+--
37+-- What this says is, given some API type @api@ that it knows it can
38+-- "mock", 'mock' hands you an implementation of the API type. It does so
39+-- by having each request handler generate a random value of the
40+-- appropriate type (@User@ in our case). All you need for this to work is
41+-- to provide 'Arbitrary' instances for the data types returned as response
42+-- bodies, hence appearing next to 'Delete', 'Get', 'Patch', 'Post' and 'Put'.
43+--
44+-- To put this all to work and run the mock server, just call 'serve' on the
45+-- result of 'mock' to get an 'Application' that you can then run with warp.
46+--
47+-- @
48+-- main :: IO ()
49+-- main = Network.Wai.Handler.Warp.run 8080 $
50+-- 'serve' myAPI ('mock' myAPI)
51+-- @
52+module Servant.Mock ( HasMock(..) ) where
53+
54+#if !MIN_VERSION_base(4,8,0)
55+import Control.Applicative
56+#endif
57+import Control.Monad.IO.Class
58+import Data.ByteString.Lazy.Char8 (pack)
59+import Data.Proxy
60+import GHC.TypeLits
61+import Network.HTTP.Types.Status
62+import Network.Wai
63+import Servant
64+import Servant.API.ContentTypes
65+import Test.QuickCheck.Arbitrary (Arbitrary (..), vector)
66+import Test.QuickCheck.Gen (Gen, generate)
67+
68+-- | 'HasMock' defines an interpretation of API types
69+-- than turns them into random-response-generating
70+-- request handlers, hence providing an instance for
71+-- all the combinators of the core /servant/ library.
72+class HasServer api => HasMock api where
73+ -- | Calling this method creates request handlers of
74+ -- the right type to implement the API described by
75+ -- @api@ that just generate random response values of
76+ -- the right type. E.g:
77+ --
78+ -- @
79+ -- type API = "user" :> Get '[JSON] User
80+ -- :<|> "book" :> Get '[JSON] Book
81+ --
82+ -- api :: Proxy API
83+ -- api = Proxy
84+ --
85+ -- -- let's say we will start with the frontend,
86+ -- -- and hence need a placeholder server
87+ -- server :: Server API
88+ -- server = mock api
89+ -- @
90+ --
91+ -- What happens here is that @'Server' API@
92+ -- actually "means" 2 request handlers, of the following types:
93+ --
94+ -- @
95+ -- getUser :: EitherT ServantErr IO User
96+ -- getBook :: EitherT ServantErr IO Book
97+ -- @
98+ --
99+ -- So under the hood, 'mock' uses the 'IO' bit to generate
100+ -- random values of type 'User' and 'Book' every time these
101+ -- endpoints are requested.
102+ mock :: Proxy api -> Server api
103+
104+instance (HasMock a, HasMock b) => HasMock (a :<|> b) where
105+ mock _ = mock (Proxy :: Proxy a) :<|> mock (Proxy :: Proxy b)
106+
107+instance (KnownSymbol path, HasMock rest) => HasMock (path :> rest) where
108+ mock _ = mock (Proxy :: Proxy rest)
109+
110+instance (KnownSymbol s, FromText a, HasMock rest) => HasMock (Capture s a :> rest) where
111+ mock _ = \_ -> mock (Proxy :: Proxy rest)
112+
113+instance (AllCTUnrender ctypes a, HasMock rest) => HasMock (ReqBody ctypes a :> rest) where
114+ mock _ = \_ -> mock (Proxy :: Proxy rest)
115+
116+instance (KnownSymbol s, FromText a, HasMock rest)
117+ => HasMock (QueryParam s a :> rest) where
118+ mock _ = \_ -> mock (Proxy :: Proxy rest)
119+
120+instance (KnownSymbol s, FromText a, HasMock rest)
121+ => HasMock (QueryParams s a :> rest) where
122+ mock _ = \_ -> mock (Proxy :: Proxy rest)
123+
124+instance (KnownSymbol s, HasMock rest) => HasMock (QueryFlag s :> rest) where
125+ mock _ = \_ -> mock (Proxy :: Proxy rest)
126+
127+instance (KnownSymbol s, FromText a, HasMock rest)
128+ => HasMock (MatrixParam s a :> rest) where
129+ mock _ = \_ -> mock (Proxy :: Proxy rest)
130+
131+instance (KnownSymbol s, FromText a, HasMock rest)
132+ => HasMock (MatrixParams s a :> rest) where
133+ mock _ = \_ -> mock (Proxy :: Proxy rest)
134+
135+instance (KnownSymbol s, HasMock rest) => HasMock (MatrixFlag s :> rest) where
136+ mock _ = \_ -> mock (Proxy :: Proxy rest)
137+
138+instance (KnownSymbol h, FromText a, HasMock rest) => HasMock (Header h a :> rest) where
139+ mock _ = \_ -> mock (Proxy :: Proxy rest)
140+
141+instance (Arbitrary a, AllCTRender ctypes a) => HasMock (Delete ctypes a) where
142+ mock _ = mockArbitrary
143+
144+instance (Arbitrary a, AllCTRender ctypes a) => HasMock (Get ctypes a) where
145+ mock _ = mockArbitrary
146+
147+instance (Arbitrary a, AllCTRender ctypes a) => HasMock (Patch ctypes a) where
148+ mock _ = mockArbitrary
149+
150+instance (Arbitrary a, AllCTRender ctypes a) => HasMock (Post ctypes a) where
151+ mock _ = mockArbitrary
152+
153+instance (Arbitrary a, AllCTRender ctypes a) => HasMock (Put ctypes a) where
154+ mock _ = mockArbitrary
155+
156+instance HasMock Raw where
157+ mock _ = \_ respond -> do
158+ bdy <- genBody
159+ respond $ responseLBS status200 [] bdy
160+
161+ where genBody = pack <$> generate (vector 100 :: Gen [Char])
162+
163+mockArbitrary :: (MonadIO m, Arbitrary a) => m a
164+mockArbitrary = liftIO (generate arbitrary)
165+
166+-- utility instance
167+instance (Arbitrary (HList ls), Arbitrary a)
168+ => Arbitrary (Headers ls a) where
169+ arbitrary = Headers <$> arbitrary <*> arbitrary
170+
171+instance Arbitrary (HList '[]) where
172+ arbitrary = pure HNil
173+
174+instance (Arbitrary a, Arbitrary (HList hs))
175+ => Arbitrary (HList (Header h a ': hs)) where
176+ arbitrary = HCons <$> fmap Header arbitrary <*> arbitrary
177+
178+
servant-server/CHANGELOG.md+5
@@ -1,3 +1,8 @@
1+0.4.3
2+-----
3+
4+* Bump aeson upper-bound to < 0.11
5+
10.4.1
60.4.1
2-----
7-----
3* Bump attoparsec upper bound to < 0.14
8* Bump attoparsec upper bound to < 0.14
servant-server/README.md+3−3
@@ -4,13 +4,13 @@
4
4
5This library lets you *implement* an HTTP server with handlers for each endpoint of a servant API, handling most of the boilerplate for you.
5This library lets you *implement* an HTTP server with handlers for each endpoint of a servant API, handling most of the boilerplate for you.
6
6
7−## Getting started
7+## Tutorial
8
8
9−We've written a [Getting Started](http://haskell-servant.github.io/getting-started/) guide that introduces the core types and features of servant. After this article, you should be able to write your first servant webservices, learning the rest from the haddocks' examples.
9+We've written a [tutorial](http://haskell-servant.github.io/tutorial/) that introduces the core types and features of servant.
10
10
11## Repositories and Haddocks
11## Repositories and Haddocks
12
12
13−- The core [servant](http://github.com/haskell-servant) package - [docs](http://hackage.haskell.org/package/servant)
13+- The core [servant](http://github.com/haskell-servant/servant/tree/master/servant) package - [docs](http://hackage.haskell.org/package/servant)
14- Implementing an HTTP server for a webservice API with [servant-server](http://github.com/haskell-servant/servant/tree/master/servant-server) - [docs](http://hackage.haskell.org/package/servant-server)
14- Implementing an HTTP server for a webservice API with [servant-server](http://github.com/haskell-servant/servant/tree/master/servant-server) - [docs](http://hackage.haskell.org/package/servant-server)
15- (Haskell) client-side function generation with [servant-client](http://github.com/haskell-servant/servant/tree/master/servant-client) - [docs](http://hackage.haskell.org/package/servant-client)
15- (Haskell) client-side function generation with [servant-client](http://github.com/haskell-servant/servant/tree/master/servant-client) - [docs](http://hackage.haskell.org/package/servant-client)
16- (Javascript) client-side function generation with [servant-jquery](http://github.com/haskell-servant/servant/tree/master/servant-jquery) - [docs](http://hackage.haskell.org/package/servant-jquery)
16- (Javascript) client-side function generation with [servant-jquery](http://github.com/haskell-servant/servant/tree/master/servant-jquery) - [docs](http://hackage.haskell.org/package/servant-jquery)
servant-server/servant-server.cabal+9−7
@@ -1,5 +1,5 @@
1name: servant-server
1name: servant-server
2−version: 0.4.1
2+version: 0.4.4.6
3synopsis: A family of combinators for defining webservices APIs and serving them
3synopsis: A family of combinators for defining webservices APIs and serving them
4description:
4description:
5 A family of combinators for defining webservices APIs and serving them
5 A family of combinators for defining webservices APIs and serving them
@@ -25,9 +25,10 @@ tested-with: GHC >= 7.8
25extra-source-files:
25extra-source-files:
26 CHANGELOG.md
26 CHANGELOG.md
27 README.md
27 README.md
28+bug-reports: http://github.com/haskell-servant/servant/issues
28source-repository head
29source-repository head
29 type: git
30 type: git
30− location: http://github.com/haskell-servant/servant-server.git
31+ location: http://github.com/haskell-servant/servant.git
31
32
32
33
33library
34library
@@ -40,25 +41,26 @@ library
40 Servant.Utils.StaticFiles
41 Servant.Utils.StaticFiles
41 build-depends:
42 build-depends:
42 base >= 4.7 && < 5
43 base >= 4.7 && < 5
43− , aeson >= 0.7 && < 0.10
44+ , aeson >= 0.7 && < 0.12
44 , attoparsec >= 0.12 && < 0.14
45 , attoparsec >= 0.12 && < 0.14
45 , bytestring >= 0.10 && < 0.11
46 , bytestring >= 0.10 && < 0.11
46 , either >= 4.3 && < 4.5
47 , either >= 4.3 && < 4.5
47− , http-types >= 0.8 && < 0.9
48+ , http-types >= 0.8 && < 0.10
48 , network-uri >= 2.6 && < 2.7
49 , network-uri >= 2.6 && < 2.7
49 , mtl >= 2 && < 3
50 , mtl >= 2 && < 3
50 , mmorph >= 1
51 , mmorph >= 1
51 , safe >= 0.3 && < 0.4
52 , safe >= 0.3 && < 0.4
52 , servant == 0.4.*
53 , servant == 0.4.*
53 , split >= 0.2 && < 0.3
54 , split >= 0.2 && < 0.3
54− , string-conversions >= 0.3 && < 0.4
55+ , string-conversions >= 0.3 && < 0.5
55 , system-filepath >= 0.4 && < 0.5
56 , system-filepath >= 0.4 && < 0.5
56 , filepath >= 1
57 , filepath >= 1
57 , text >= 1.2 && < 1.3
58 , text >= 1.2 && < 1.3
58 , transformers >= 0.3 && < 0.5
59 , transformers >= 0.3 && < 0.5
59− , wai >= 3.0 && < 3.1
60+ , wai >= 3.0 && < 3.3
60 , wai-app-static >= 3.0 && < 3.2
61 , wai-app-static >= 3.0 && < 3.2
61− , warp >= 3.0 && < 3.1
62+ , warp >= 3.0 && < 3.3
63+
62 hs-source-dirs: src
64 hs-source-dirs: src
63 default-language: Haskell2010
65 default-language: Haskell2010
64 ghc-options: -Wall
66 ghc-options: -Wall
servant/CHANGELOG.md+4
@@ -1,3 +1,7 @@
1+0.4.3
2+-----
3+* Add missing HasLink instance for Header (https://github.com/haskell-servant/servant/issues/128)
4+
10.4.1
50.4.1
2-----
6-----
3* Allow whitespace after parsing JSON
7* Allow whitespace after parsing JSON
servant/servant.cabal+3−6
@@ -1,14 +1,11 @@
1name: servant
1name: servant
2−version: 0.4.1
2+version: 0.4.4.6
3synopsis: A family of combinators for defining webservices APIs
3synopsis: A family of combinators for defining webservices APIs
4description:
4description:
5 A family of combinators for defining webservices APIs and serving them
5 A family of combinators for defining webservices APIs and serving them
6 .
6 .
7 You can learn about the basics in the <http://haskell-servant.github.io/tutorial tutorial>.
7 You can learn about the basics in the <http://haskell-servant.github.io/tutorial tutorial>.
8 .
8 .
9− <https://github.com/haskell-servant/servant-server/blob/master/example/greet.hs Here>'s a runnable example, with comments, that defines a dummy API and
10− implements a webserver that serves this API, using the <http://hackage.haskell.org/package/servant-server servant-server> package.
11− .
12 <https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md CHANGELOG>
9 <https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md CHANGELOG>
13homepage: http://haskell-servant.github.io/
10homepage: http://haskell-servant.github.io/
14Bug-reports: http://github.com/haskell-servant/servant/issues
11Bug-reports: http://github.com/haskell-servant/servant/issues
@@ -53,9 +50,9 @@ library
53 , bytestring-conversion == 0.3.*
50 , bytestring-conversion == 0.3.*
54 , case-insensitive >= 1.2
51 , case-insensitive >= 1.2
55 , http-media >= 0.4 && < 0.7
52 , http-media >= 0.4 && < 0.7
56− , http-types == 0.8.*
53+ , http-types >= 0.8 && < 0.10
57 , text >= 1 && < 2
54 , text >= 1 && < 2
58− , string-conversions >= 0.3 && < 0.4
55+ , string-conversions >= 0.3 && < 0.5
59 , network-uri >= 2.6
56 , network-uri >= 2.6
60 hs-source-dirs: src
57 hs-source-dirs: src
61 default-language: Haskell2010
58 default-language: Haskell2010
servant/src/Servant/API/ContentTypes.hs+1−1
@@ -166,7 +166,7 @@ instance ( AllMimeRender ctyps a, IsNonEmpty ctyps
166 handleAcceptH _ (AcceptHeader accept) val = M.mapAcceptMedia lkup accept
166 handleAcceptH _ (AcceptHeader accept) val = M.mapAcceptMedia lkup accept
167 where pctyps = Proxy :: Proxy ctyps
167 where pctyps = Proxy :: Proxy ctyps
168 amrs = allMimeRender pctyps val
168 amrs = allMimeRender pctyps val
169− lkup = fmap (\(a,b) -> (a, (cs $ show a, b))) amrs
169+ lkup = fmap (\(a,b) -> (a, (fromStrict $ M.renderHeader a, b))) amrs
170
170
171
171
172--------------------------------------------------------------------------
172--------------------------------------------------------------------------
servant/src/Servant/Utils/Links.hs+4
@@ -339,6 +339,10 @@ instance (ToText v, HasLink sub)
339 toLink (Proxy :: Proxy sub) $
339 toLink (Proxy :: Proxy sub) $
340 addSegment (escape . unpack $ toText v) l
340 addSegment (escape . unpack $ toText v) l
341
341
342+instance HasLink sub => HasLink (Header sym a :> sub) where
343+ type MkLink (Header sym a :> sub) = MkLink sub
344+ toLink _ = toLink (Proxy :: Proxy sub)
345+
342-- Verb (terminal) instances
346-- Verb (terminal) instances
343instance HasLink (Get y r) where
347instance HasLink (Get y r) where
344 type MkLink (Get y r) = URI
348 type MkLink (Get y r) = URI
servant/test/Servant/API/ContentTypesSpec.hs+1
@@ -4,6 +4,7 @@
4{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE OverloadedStrings #-}
6{-# OPTIONS_GHC -fno-warn-orphans #-}
6{-# OPTIONS_GHC -fno-warn-orphans #-}
7+
7module Servant.API.ContentTypesSpec where
8module Servant.API.ContentTypesSpec where
8
9
9#if !MIN_VERSION_base(4,8,0)
10#if !MIN_VERSION_base(4,8,0)
sources.txt+2
@@ -1,4 +1,5 @@
1servant
1servant
2+servant-cassava
2servant-client
3servant-client
3servant-docs
4servant-docs
4servant-jquery
5servant-jquery
@@ -6,3 +7,4 @@ servant-server
6servant-examples
7servant-examples
7servant-blaze
8servant-blaze
8servant-lucid
9servant-lucid
10+servant-mock
stack.yamlnew file+15
@@ -0,0 +1,15 @@
1+packages:
2+- servant/
3+- servant-blaze/
4+- servant-client/
5+- servant-docs/
6+- servant-examples/
7+- servant-jquery/
8+- servant-lucid/
9+- servant-mock/
10+- servant-server/
11+extra-deps:
12+- engine-io-wai-1.0.2
13+- attoparsec-0.13.0.1
14+- aeson-0.10.0.0
15+resolver: nightly-2015-07-24