on 654b092 help sign in
.travis.yml+36−38
since splitsnapshots
unifiedsplit
@@ -2,7 +2,7 @@
2#
2#
3# runghc make_travis_yml_2.hs '--config=cabal.make-travis-yml' '--output=.travis.yml' 'cabal.project'
3# runghc make_travis_yml_2.hs '--config=cabal.make-travis-yml' '--output=.travis.yml' 'cabal.project'
4#
4#
5−# For more information, see https://github.com/hvr/multi-ghc-travis
5+# For more information, see https://github.com/haskell-CI/haskell-ci
6#
6#
7language: c
7language: c
8sudo: false
8sudo: false
@@ -13,7 +13,7 @@ git:
13branches:
13branches:
14 only:
14 only:
15 - master
15 - master
16− - release-0.12
16+ - release-0.14
17
17
18cache:
18cache:
19 directories:
19 directories:
@@ -33,21 +33,24 @@ before_cache:
33
33
34matrix:
34matrix:
35 include:
35 include:
36− - compiler: "ghc-8.4.3"
36+ - compiler: "ghc-8.6.1"
37 # env: TEST=--disable-tests BENCH=--disable-benchmarks
37 # env: TEST=--disable-tests BENCH=--disable-benchmarks
38− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}
38+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}
39+ - compiler: "ghc-8.4.4"
40+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
41+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}
39 - compiler: "ghc-8.2.2"
42 - compiler: "ghc-8.2.2"
40 # env: TEST=--disable-tests BENCH=--disable-benchmarks
43 # env: TEST=--disable-tests BENCH=--disable-benchmarks
41− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}
44+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}
42 - compiler: "ghc-8.0.2"
45 - compiler: "ghc-8.0.2"
43 # env: TEST=--disable-tests BENCH=--disable-benchmarks
46 # env: TEST=--disable-tests BENCH=--disable-benchmarks
44− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}
47+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}
45 - compiler: "ghc-7.10.3"
48 - compiler: "ghc-7.10.3"
46 # env: TEST=--disable-tests BENCH=--disable-benchmarks
49 # env: TEST=--disable-tests BENCH=--disable-benchmarks
47− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}
50+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3], sources: [hvr-ghc]}}
48 - compiler: "ghc-7.8.4"
51 - compiler: "ghc-7.8.4"
49 # env: TEST=--disable-tests BENCH=--disable-benchmarks
52 # env: TEST=--disable-tests BENCH=--disable-benchmarks
50− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}
53+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4], sources: [hvr-ghc]}}
51
54
52before_install:
55before_install:
53 - HC=${CC}
56 - HC=${CC}
@@ -65,17 +68,21 @@ install:
65 - BENCH=${BENCH---enable-benchmarks}
68 - BENCH=${BENCH---enable-benchmarks}
66 - TEST=${TEST---enable-tests}
69 - TEST=${TEST---enable-tests}
67 - HADDOCK=${HADDOCK-true}
70 - HADDOCK=${HADDOCK-true}
68− - INSTALLED=${INSTALLED-true}
71+ - UNCONSTRAINED=${UNCONSTRAINED-true}
72+ - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}
69 - GHCHEAD=${GHCHEAD-false}
73 - GHCHEAD=${GHCHEAD-false}
70 - travis_retry cabal update -v
74 - travis_retry cabal update -v
71 - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"
75 - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"
72 - rm -fv cabal.project cabal.project.local
76 - rm -fv cabal.project cabal.project.local
73 - "if [ $HCNUMVER -ge 70800 ]; then sed -i.bak 's/-- ghc-options:.*/ghc-options: -j2/' ${HOME}/.cabal/config; fi"
77 - "if [ $HCNUMVER -ge 70800 ]; then sed -i.bak 's/-- ghc-options:.*/ghc-options: -j2/' ${HOME}/.cabal/config; fi"
74 - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
78 - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
75− - "printf 'packages: \"servant\" \"servant-client\" \"servant-client-core\" \"servant-docs\" \"servant-foreign\" \"servant-server\" \"doc/tutorial\" \"doc/cookbook/basic-auth\" \"doc/cookbook/db-postgres-pool\" \"doc/cookbook/db-sqlite-simple\" \"doc/cookbook/https\" \"doc/cookbook/pagination\" \"doc/cookbook/structuring-apis\" \"doc/cookbook/using-custom-monad\"\\n' > cabal.project"
79+ - "printf 'packages: \"servant\" \"servant-client\" \"servant-client-core\" \"servant-docs\" \"servant-foreign\" \"servant-server\" \"doc/tutorial\" \"doc/cookbook/basic-auth\" \"doc/cookbook/db-postgres-pool\" \"doc/cookbook/db-sqlite-simple\" \"doc/cookbook/file-upload\" \"doc/cookbook/generic\" \"doc/cookbook/https\" \"doc/cookbook/structuring-apis\" \"doc/cookbook/using-custom-monad\"\\n' > cabal.project"
76− - "echo 'constraints: foundation >=0.0.14,memory <0.14.12 || >0.14.12' >> cabal.project"
80+ - "echo 'constraints: foundation >=0.0.14,memory <0.14.12 || >0.14.12, containers installed' >> cabal.project"
77− - "echo 'allow-newer: servant-auth-server:http-types,servant-auth-server:servant-server, http-media:base' >> cabal.project"
81+ - "echo 'allow-newer: servant-auth-server:http-types,servant-auth-server:servant-server, servant-js:base,servant-pagination:servant,servant-pagination:servant-server' >> cabal.project"
82+ - touch cabal.project.local
83+ - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-client-core | grep -vw -- servant-docs | grep -vw -- servant-foreign | grep -vw -- servant-server | grep -vw -- tutorial | grep -vw -- cookbook-basic-auth | grep -vw -- cookbook-db-postgres-pool | grep -vw -- cookbook-db-sqlite-simple | grep -vw -- cookbook-file-upload | grep -vw -- cookbook-generic | grep -vw -- cookbook-https | grep -vw -- cookbook-structuring-apis | grep -vw -- cookbook-using-custom-monad | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"
78− - cat cabal.project
84+ - cat cabal.project || true
85+ - cat cabal.project.local || true
79 - if [ -f "servant/configure.ac" ]; then
86 - if [ -f "servant/configure.ac" ]; then
80 (cd "servant" && autoreconf -i);
87 (cd "servant" && autoreconf -i);
81 fi
88 fi
@@ -106,12 +113,15 @@ install:
106 - if [ -f "doc/cookbook/db-sqlite-simple/configure.ac" ]; then
113 - if [ -f "doc/cookbook/db-sqlite-simple/configure.ac" ]; then
107 (cd "doc/cookbook/db-sqlite-simple" && autoreconf -i);
114 (cd "doc/cookbook/db-sqlite-simple" && autoreconf -i);
108 fi
115 fi
116+ - if [ -f "doc/cookbook/file-upload/configure.ac" ]; then
117+ (cd "doc/cookbook/file-upload" && autoreconf -i);
118+ fi
119+ - if [ -f "doc/cookbook/generic/configure.ac" ]; then
120+ (cd "doc/cookbook/generic" && autoreconf -i);
121+ fi
109 - if [ -f "doc/cookbook/https/configure.ac" ]; then
122 - if [ -f "doc/cookbook/https/configure.ac" ]; then
110 (cd "doc/cookbook/https" && autoreconf -i);
123 (cd "doc/cookbook/https" && autoreconf -i);
111 fi
124 fi
112− - if [ -f "doc/cookbook/pagination/configure.ac" ]; then
113− (cd "doc/cookbook/pagination" && autoreconf -i);
114− fi
115 - if [ -f "doc/cookbook/structuring-apis/configure.ac" ]; then
125 - if [ -f "doc/cookbook/structuring-apis/configure.ac" ]; then
116 (cd "doc/cookbook/structuring-apis" && autoreconf -i);
126 (cd "doc/cookbook/structuring-apis" && autoreconf -i);
117 fi
127 fi
@@ -119,7 +129,7 @@ install:
119 (cd "doc/cookbook/using-custom-monad" && autoreconf -i);
129 (cd "doc/cookbook/using-custom-monad" && autoreconf -i);
120 fi
130 fi
121 - rm -f cabal.project.freeze
131 - rm -f cabal.project.freeze
122− - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-client-core"/dist "servant-docs"/dist "servant-foreign"/dist "servant-server"/dist "doc/tutorial"/dist "doc/cookbook/basic-auth"/dist "doc/cookbook/db-postgres-pool"/dist "doc/cookbook/db-sqlite-simple"/dist "doc/cookbook/https"/dist "doc/cookbook/pagination"/dist "doc/cookbook/structuring-apis"/dist "doc/cookbook/using-custom-monad"/dist
132+ - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-client-core"/dist "servant-docs"/dist "servant-foreign"/dist "servant-server"/dist "doc/tutorial"/dist "doc/cookbook/basic-auth"/dist "doc/cookbook/db-postgres-pool"/dist "doc/cookbook/db-sqlite-simple"/dist "doc/cookbook/file-upload"/dist "doc/cookbook/generic"/dist "doc/cookbook/https"/dist "doc/cookbook/structuring-apis"/dist "doc/cookbook/using-custom-monad"/dist
123 - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
133 - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
124
134
125# Here starts the actual work to be performed for the package under test;
135# Here starts the actual work to be performed for the package under test;
@@ -127,32 +137,21 @@ install:
127script:
137script:
128 # test that source-distributions can be generated
138 # test that source-distributions can be generated
129 - echo Packaging... && echo -en 'travis_fold:start:sdist\\r'
139 - echo Packaging... && echo -en 'travis_fold:start:sdist\\r'
130− - (cd "servant" && cabal sdist)
140+ - cabal new-sdist all
131− - (cd "servant-client" && cabal sdist)
132− - (cd "servant-client-core" && cabal sdist)
133− - (cd "servant-docs" && cabal sdist)
134− - (cd "servant-foreign" && cabal sdist)
135− - (cd "servant-server" && cabal sdist)
136− - (cd "doc/tutorial" && cabal sdist)
137− - (cd "doc/cookbook/basic-auth" && cabal sdist)
138− - (cd "doc/cookbook/db-postgres-pool" && cabal sdist)
139− - (cd "doc/cookbook/db-sqlite-simple" && cabal sdist)
140− - (cd "doc/cookbook/https" && cabal sdist)
141− - (cd "doc/cookbook/pagination" && cabal sdist)
142− - (cd "doc/cookbook/structuring-apis" && cabal sdist)
143− - (cd "doc/cookbook/using-custom-monad" && cabal sdist)
144 - echo -en 'travis_fold:end:sdist\\r'
141 - echo -en 'travis_fold:end:sdist\\r'
145 - echo Unpacking... && echo -en 'travis_fold:start:unpack\\r'
142 - echo Unpacking... && echo -en 'travis_fold:start:unpack\\r'
146− - mv "servant"/dist/servant-*.tar.gz "servant-client"/dist/servant-client-*.tar.gz "servant-client-core"/dist/servant-client-core-*.tar.gz "servant-docs"/dist/servant-docs-*.tar.gz "servant-foreign"/dist/servant-foreign-*.tar.gz "servant-server"/dist/servant-server-*.tar.gz "doc/tutorial"/dist/tutorial-*.tar.gz "doc/cookbook/basic-auth"/dist/cookbook-basic-auth-*.tar.gz "doc/cookbook/db-postgres-pool"/dist/cookbook-db-postgres-pool-*.tar.gz "doc/cookbook/db-sqlite-simple"/dist/cookbook-db-sqlite-simple-*.tar.gz "doc/cookbook/https"/dist/cookbook-https-*.tar.gz "doc/cookbook/pagination"/dist/cookbook-pagination-*.tar.gz "doc/cookbook/structuring-apis"/dist/cookbook-structuring-apis-*.tar.gz "doc/cookbook/using-custom-monad"/dist/cookbook-using-custom-monad-*.tar.gz ${DISTDIR}/
143+ - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
147 - cd ${DISTDIR} || false
144 - cd ${DISTDIR} || false
148 - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
145 - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
149− - "printf 'packages: servant-*/*.cabal servant-client-*/*.cabal servant-client-core-*/*.cabal servant-docs-*/*.cabal servant-foreign-*/*.cabal servant-server-*/*.cabal tutorial-*/*.cabal cookbook-basic-auth-*/*.cabal cookbook-db-postgres-pool-*/*.cabal cookbook-db-sqlite-simple-*/*.cabal cookbook-https-*/*.cabal cookbook-pagination-*/*.cabal cookbook-structuring-apis-*/*.cabal cookbook-using-custom-monad-*/*.cabal\\n' > cabal.project"
146+ - "printf 'packages: servant-*/*.cabal servant-client-*/*.cabal servant-client-core-*/*.cabal servant-docs-*/*.cabal servant-foreign-*/*.cabal servant-server-*/*.cabal tutorial-*/*.cabal cookbook-basic-auth-*/*.cabal cookbook-db-postgres-pool-*/*.cabal cookbook-db-sqlite-simple-*/*.cabal cookbook-file-upload-*/*.cabal cookbook-generic-*/*.cabal cookbook-https-*/*.cabal cookbook-structuring-apis-*/*.cabal cookbook-using-custom-monad-*/*.cabal\\n' > cabal.project"
150− - "echo 'constraints: foundation >=0.0.14,memory <0.14.12 || >0.14.12' >> cabal.project"
147+ - "echo 'constraints: foundation >=0.0.14,memory <0.14.12 || >0.14.12, containers installed' >> cabal.project"
151− - "echo 'allow-newer: servant-auth-server:http-types,servant-auth-server:servant-server, http-media:base' >> cabal.project"
148+ - "echo 'allow-newer: servant-auth-server:http-types,servant-auth-server:servant-server, servant-js:base,servant-pagination:servant,servant-pagination:servant-server' >> cabal.project"
149+ - touch cabal.project.local
150+ - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-client-core | grep -vw -- servant-docs | grep -vw -- servant-foreign | grep -vw -- servant-server | grep -vw -- tutorial | grep -vw -- cookbook-basic-auth | grep -vw -- cookbook-db-postgres-pool | grep -vw -- cookbook-db-sqlite-simple | grep -vw -- cookbook-file-upload | grep -vw -- cookbook-generic | grep -vw -- cookbook-https | grep -vw -- cookbook-structuring-apis | grep -vw -- cookbook-using-custom-monad | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"
152− - cat cabal.project
151+ - cat cabal.project || true
152+ - cat cabal.project.local || true
153 - echo -en 'travis_fold:end:unpack\\r'
153 - echo -en 'travis_fold:end:unpack\\r'
154
154
155−
156 - echo Building with tests and benchmarks... && echo -en 'travis_fold:start:build-everything\\r'
155 - echo Building with tests and benchmarks... && echo -en 'travis_fold:start:build-everything\\r'
157 # build & run tests, build benchmarks
156 # build & run tests, build benchmarks
158 - cabal new-build -w ${HC} ${TEST} ${BENCH} all
157 - cabal new-build -w ${HC} ${TEST} ${BENCH} all
@@ -161,7 +160,6 @@ script:
161
160
162 - echo Haddock... && echo -en 'travis_fold:start:haddock\\r'
161 - echo Haddock... && echo -en 'travis_fold:start:haddock\\r'
163 # haddock
162 # haddock
164− - rm -rf ./dist-newstyle
165 - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi
163 - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi
166
164
167 - echo -en 'travis_fold:end:haddock\\r'
165 - echo -en 'travis_fold:end:haddock\\r'
cabal.make-travis-yml+2−2
@@ -1,12 +1,12 @@
1folds: all-but-test
1folds: all-but-test
2−branches: master release-0.12
2+branches: master release-0.14
3
3
4-- We have inplace packages (servant-js) so we skip installing dependencies in a separate step
4-- We have inplace packages (servant-js) so we skip installing dependencies in a separate step
5install-dependencies-step: False
5install-dependencies-step: False
6
6
7-- this speed-ups the build a little, but we have to check these for release
7-- this speed-ups the build a little, but we have to check these for release
8no-tests-no-benchmarks: False
8no-tests-no-benchmarks: False
9−build-with-installed-step: False
9+unconstrained-step: False
10
10
11-- Don't run cabal check, as cookbook examples won't pass it
11-- Don't run cabal check, as cookbook examples won't pass it
12cabal-check: False
12cabal-check: False
cabal.project+5−7
@@ -11,12 +11,11 @@ packages: servant/
11 doc/cookbook/basic-auth
11 doc/cookbook/basic-auth
12 doc/cookbook/db-postgres-pool
12 doc/cookbook/db-postgres-pool
13 doc/cookbook/db-sqlite-simple
13 doc/cookbook/db-sqlite-simple
14− -- MkLink changed
15− -- doc/cookbook/file-upload
14+ doc/cookbook/file-upload
15+ doc/cookbook/generic
16 doc/cookbook/https
16 doc/cookbook/https
17− -- servant-auth-* doesn't support GHC-8.4
18 -- doc/cookbook/jwt-and-basic-auth
17 -- doc/cookbook/jwt-and-basic-auth
19− doc/cookbook/pagination
18+ -- doc/cookbook/pagination
20 doc/cookbook/structuring-apis
19 doc/cookbook/structuring-apis
21 doc/cookbook/using-custom-monad
20 doc/cookbook/using-custom-monad
22
21
@@ -29,10 +28,9 @@ constraints:
29 foundation >=0.0.14,
28 foundation >=0.0.14,
30 memory <0.14.12 || >0.14.12
29 memory <0.14.12 || >0.14.12
31
30
32−allow-newer:
31+constraints: containers installed
33− http-media:base
34
32
35allow-newer:
33allow-newer:
36− servant-js:servant,
34+ servant-js:base,
37 servant-pagination:servant,
35 servant-pagination:servant,
38 servant-pagination:servant-server
36 servant-pagination:servant-server
doc/Makefile+10−206
@@ -1,216 +1,20 @@
1−# Makefile for Sphinx documentation
1+# Minimal makefile for Sphinx documentation
2#
2#
3
3
4# You can set these variables from the command line.
4# You can set these variables from the command line.
5SPHINXOPTS =
5SPHINXOPTS =
6SPHINXBUILD = sphinx-build
6SPHINXBUILD = sphinx-build
7−PAPER =
7+SPHINXPROJ = Servant
8+SOURCEDIR = .
8BUILDDIR = _build
9BUILDDIR = _build
9
10
10−# User-friendly check for sphinx-build
11+# Put it first so that "make" without argument is like "make help".
11−ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12−$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13−endif
14−
15−# Internal variables.
16−PAPEROPT_a4 = -D latex_paper_size=a4
17−PAPEROPT_letter = -D latex_paper_size=letter
18−ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19−# the i18n builder cannot share the environment and doctrees with the others
20−I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21−
22−.PHONY: help
23help:
12help:
24− @echo "Please use \`make <target>' where <target> is one of"
13+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
25− @echo " html to make standalone HTML files"
26− @echo " dirhtml to make HTML files named index.html in directories"
27− @echo " singlehtml to make a single large HTML file"
28− @echo " pickle to make pickle files"
29− @echo " json to make JSON files"
30− @echo " htmlhelp to make HTML files and a HTML help project"
31− @echo " qthelp to make HTML files and a qthelp project"
32− @echo " applehelp to make an Apple Help Book"
33− @echo " devhelp to make HTML files and a Devhelp project"
34− @echo " epub to make an epub"
35− @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36− @echo " latexpdf to make LaTeX files and run them through pdflatex"
37− @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38− @echo " text to make text files"
39− @echo " man to make manual pages"
40− @echo " texinfo to make Texinfo files"
41− @echo " info to make Texinfo files and run them through makeinfo"
42− @echo " gettext to make PO message catalogs"
43− @echo " changes to make an overview of all changed/added/deprecated items"
44− @echo " xml to make Docutils-native XML files"
45− @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46− @echo " linkcheck to check all external links for integrity"
47− @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48− @echo " coverage to run coverage check of the documentation (if enabled)"
49−
50−.PHONY: clean
51−clean:
52− rm -rf $(BUILDDIR)/*
53−
54−.PHONY: html
55−html:
56− $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
57− @echo
58− @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
59−
60−.PHONY: dirhtml
61−dirhtml:
62− $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
63− @echo
64− @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
65−
66−.PHONY: singlehtml
67−singlehtml:
68− $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
69− @echo
70− @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
71−
72−.PHONY: pickle
73−pickle:
74− $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
75− @echo
76− @echo "Build finished; now you can process the pickle files."
77−
78−.PHONY: json
79−json:
80− $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
81− @echo
82− @echo "Build finished; now you can process the JSON files."
83−
84−.PHONY: htmlhelp
85−htmlhelp:
86− $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
87− @echo
88− @echo "Build finished; now you can run HTML Help Workshop with the" \
89− ".hhp project file in $(BUILDDIR)/htmlhelp."
90−
91−.PHONY: qthelp
92−qthelp:
93− $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
94− @echo
95− @echo "Build finished; now you can run "qcollectiongenerator" with the" \
96− ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
97− @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/generics-eot.qhcp"
98− @echo "To view the help file:"
99− @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/generics-eot.qhc"
100−
101−.PHONY: applehelp
102−applehelp:
103− $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
104− @echo
105− @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
106− @echo "N.B. You won't be able to view it unless you put it in" \
107− "~/Library/Documentation/Help or install it in your application" \
108− "bundle."
109−
110−.PHONY: devhelp
111−devhelp:
112− $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
113− @echo
114− @echo "Build finished."
115− @echo "To view the help file:"
116− @echo "# mkdir -p $$HOME/.local/share/devhelp/generics-eot"
117− @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/generics-eot"
118− @echo "# devhelp"
119−
120−.PHONY: epub
121−epub:
122− $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
123− @echo
124− @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
125−
126−.PHONY: latex
127−latex:
128− $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
129− @echo
130− @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
131− @echo "Run \`make' in that directory to run these through (pdf)latex" \
132− "(use \`make latexpdf' here to do that automatically)."
133−
134−.PHONY: latexpdf
135−latexpdf:
136− $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
137− @echo "Running LaTeX files through pdflatex..."
138− $(MAKE) -C $(BUILDDIR)/latex all-pdf
139− @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
140−
141−.PHONY: latexpdfja
142−latexpdfja:
143− $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
144− @echo "Running LaTeX files through platex and dvipdfmx..."
145− $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
146− @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
147−
148−.PHONY: text
149−text:
150− $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
151− @echo
152− @echo "Build finished. The text files are in $(BUILDDIR)/text."
153−
154−.PHONY: man
155−man:
156− $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
157− @echo
158− @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
159−
160−.PHONY: texinfo
161−texinfo:
162− $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
163− @echo
164− @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
165− @echo "Run \`make' in that directory to run these through makeinfo" \
166− "(use \`make info' here to do that automatically)."
167−
168−.PHONY: info
169−info:
170− $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
171− @echo "Running Texinfo files through makeinfo..."
172− make -C $(BUILDDIR)/texinfo info
173− @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
174−
175−.PHONY: gettext
176−gettext:
177− $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
178− @echo
179− @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
180−
181−.PHONY: changes
182−changes:
183− $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
184− @echo
185− @echo "The overview file is in $(BUILDDIR)/changes."
186−
187−.PHONY: linkcheck
188−linkcheck:
189− $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
190− @echo
191− @echo "Link check complete; look for any errors in the above output " \
192− "or in $(BUILDDIR)/linkcheck/output.txt."
193−
194−.PHONY: doctest
195−doctest:
196− $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
197− @echo "Testing of doctests in the sources finished, look at the " \
198− "results in $(BUILDDIR)/doctest/output.txt."
199−
200−.PHONY: coverage
201−coverage:
202− $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
203− @echo "Testing of coverage in the sources finished, look at the " \
204− "results in $(BUILDDIR)/coverage/python.txt."
205
14
206−.PHONY: xml
15+.PHONY: help Makefile
207−xml:
208− $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
209− @echo
210− @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
211
16
212−.PHONY: pseudoxml
17+# Catch-all target: route all unknown targets to Sphinx using the new
213−pseudoxml:
18+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+%: Makefile
214− $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
20+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
215− @echo
216− @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
doc/conf.py+54−175
@@ -1,7 +1,7 @@
1# -*- coding: utf-8 -*-
1# -*- coding: utf-8 -*-
2#
2#
3−# servant documentation build configuration file, created by
3+# Servant documentation build configuration file, created by
4−# sphinx-quickstart on Mon Nov 23 13:24:36 2015.
4+# sphinx-quickstart on Fri Jul 6 11:38:51 2018.
5#
5#
6# This file is execfile()d with the current directory set to its
6# This file is execfile()d with the current directory set to its
7# containing dir.
7# containing dir.
@@ -12,20 +12,21 @@
12# All configuration values have a default; values that are commented out
12# All configuration values have a default; values that are commented out
13# serve to show the default.
13# serve to show the default.
14
14
15−import sys
16−import os
17−import shlex
18−from recommonmark.parser import CommonMarkParser
19−
20# If extensions (or modules to document with autodoc) are in another directory,
15# If extensions (or modules to document with autodoc) are in another directory,
21# add these directories to sys.path here. If the directory is relative to the
16# add these directories to sys.path here. If the directory is relative to the
22# documentation root, use os.path.abspath to make it absolute, like shown here.
17# documentation root, use os.path.abspath to make it absolute, like shown here.
18+#
19+# import os
20+# import sys
23−#sys.path.insert(0, os.path.abspath('.'))
21+# sys.path.insert(0, os.path.abspath('.'))
22+from recommonmark.parser import CommonMarkParser
23+
24
24
25# -- General configuration ------------------------------------------------
25# -- General configuration ------------------------------------------------
26
26
27# If your documentation needs a minimal Sphinx version, state it here.
27# If your documentation needs a minimal Sphinx version, state it here.
28+#
28−#needs_sphinx = '1.0'
29+# needs_sphinx = '1.0'
29
30
30# Add any Sphinx extension module names here, as strings. They can be
31# Add any Sphinx extension module names here, as strings. They can be
31# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
32# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -37,17 +38,15 @@ templates_path = ['_templates']
37
38
38# The suffix(es) of source filenames.
39# The suffix(es) of source filenames.
39# You can specify multiple suffix as a list of string:
40# You can specify multiple suffix as a list of string:
41+#
40−source_suffix = ['.md', '.rst', '.lhs']
42+source_suffix = ['.rst', '.md', '.lhs']
41−
42−# The encoding of source files.
43−#source_encoding = 'utf-8-sig'
44
43
45# The master toctree document.
44# The master toctree document.
46master_doc = 'index'
45master_doc = 'index'
47
46
48# General information about the project.
47# General information about the project.
49−project = u'servant'
48+project = u'Servant'
50−copyright = u'2016, Servant Contributors'
49+copyright = u'2018, Servant Contributors'
51author = u'Servant Contributors'
50author = u'Servant Contributors'
52
51
53# The version info for the project you're documenting, acts as replacement for
52# The version info for the project you're documenting, acts as replacement for
@@ -55,9 +54,9 @@ author = u'Servant Contributors'
55# built documents.
54# built documents.
56#
55#
57# The short X.Y version.
56# The short X.Y version.
58−# version = 'latest'
57+# version = u'0.14'
59# The full version, including alpha/beta/rc tags.
58# The full version, including alpha/beta/rc tags.
60−# release = 'latest'
59+# release = u'0.14'
61
60
62# The language for content autogenerated by Sphinx. Refer to documentation
61# The language for content autogenerated by Sphinx. Refer to documentation
63# for a list of supported languages.
62# for a list of supported languages.
@@ -66,45 +65,14 @@ author = u'Servant Contributors'
66# Usually you set "language" from the command line for these cases.
65# Usually you set "language" from the command line for these cases.
67language = None
66language = None
68
67
69−# There are two options for replacing |today|: either, you set today to some
70−# non-false value, then it is used:
71−#today = ''
72−# Else, today_fmt is used as the format for a strftime call.
73−#today_fmt = '%B %d, %Y'
74−
75# List of patterns, relative to source directory, that match files and
68# List of patterns, relative to source directory, that match files and
76# directories to ignore when looking for source files.
69# directories to ignore when looking for source files.
70+# This patterns also effect to html_static_path and html_extra_path
77−exclude_patterns = ['_build', 'venv']
71+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
78−
79−# The reST default role (used for this markup: `text`) to use for all
80−# documents.
81−#default_role = None
82−
83−# If true, '()' will be appended to :func: etc. cross-reference text.
84−#add_function_parentheses = True
85−
86−# If true, the current module name will be prepended to all description
87−# unit titles (such as .. function::).
88−#add_module_names = True
89−
90−# If true, sectionauthor and moduleauthor directives will be shown in the
91−# output. They are ignored by default.
92−#show_authors = False
93
72
94# The name of the Pygments (syntax highlighting) style to use.
73# The name of the Pygments (syntax highlighting) style to use.
95pygments_style = 'sphinx'
74pygments_style = 'sphinx'
96
75
97−def setup(app):
98− from sphinx.highlighting import lexers
99− from pygments.lexers import HaskellLexer
100− lexers['haskell ignore'] = HaskellLexer(stripnl=False)
101−
102−# A list of ignored prefixes for module index sorting.
103−#modindex_common_prefix = []
104−
105−# If true, keep warnings as "system message" paragraphs in the built documents.
106−#keep_warnings = False
107−
108# If true, `todo` and `todoList` produce output, else they produce nothing.
76# If true, `todo` and `todoList` produce output, else they produce nothing.
109todo_include_todos = False
77todo_include_todos = False
110
78
@@ -113,157 +81,77 @@ todo_include_todos = False
113
81
114# The theme to use for HTML and HTML Help pages. See the documentation for
82# The theme to use for HTML and HTML Help pages. See the documentation for
115# a list of builtin themes.
83# a list of builtin themes.
84+#
116html_theme = 'sphinx_rtd_theme'
85html_theme = 'sphinx_rtd_theme'
117
86
118# Theme options are theme-specific and customize the look and feel of a theme
87# Theme options are theme-specific and customize the look and feel of a theme
119# further. For a list of options available for each theme, see the
88# further. For a list of options available for each theme, see the
120# documentation.
89# documentation.
90+#
121−#html_theme_options = {}
91+# html_theme_options = {}
122−
123−# Add any paths that contain custom themes here, relative to this directory.
124−#html_theme_path = []
125−
126−# The name for this set of Sphinx documents. If None, it defaults to
127−# "<project> v<release> documentation".
128−#html_title = None
129−
130−# A shorter title for the navigation bar. Default is the same as html_title.
131−#html_short_title = None
132−
133−# The name of an image file (relative to this directory) to place at the top
134−# of the sidebar.
135−#html_logo = None
136−
137−# The name of an image file (within the static path) to use as favicon of the
138−# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
139−# pixels large.
140−#html_favicon = None
141
92
142# Add any paths that contain custom static files (such as style sheets) here,
93# Add any paths that contain custom static files (such as style sheets) here,
143# relative to this directory. They are copied after the builtin static files,
94# relative to this directory. They are copied after the builtin static files,
144# so a file named "default.css" will overwrite the builtin "default.css".
95# so a file named "default.css" will overwrite the builtin "default.css".
145html_static_path = ['_static']
96html_static_path = ['_static']
146
97
147−# Add any extra paths that contain custom files (such as robots.txt or
148−# .htaccess) here, relative to this directory. These files are copied
149−# directly to the root of the documentation.
150−#html_extra_path = []
151−
152−# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
153−# using the given strftime format.
154−#html_last_updated_fmt = '%b %d, %Y'
155−
156−# If true, SmartyPants will be used to convert quotes and dashes to
157−# typographically correct entities.
158−#html_use_smartypants = True
159−
160−# Custom sidebar templates, maps document names to template names.
98+# Custom sidebar templates, must be a dictionary that maps document names
99+# to template names.
100+#
101+# This is required for the alabaster theme
102+# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
161−#html_sidebars = {}
103+html_sidebars = {
162−
104+ '**': [
163−# Additional templates that should be rendered to pages, maps page names to
105+ 'relations.html', # needs 'show_related': True theme option to display
164−# template names.
106+ 'searchbox.html',
165−#html_additional_pages = {}
107+ ]
166−
108+}
167−# If false, no module index is generated.
168−#html_domain_indices = True
169−
170−# If false, no index is generated.
171−#html_use_index = True
172−
173−# If true, the index is split into individual pages for each letter.
174−#html_split_index = False
175−
176−# If true, links to the reST sources are added to the pages.
177−#html_show_sourcelink = True
178−
179−# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
180−#html_show_sphinx = True
181−
182−# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
183−#html_show_copyright = True
184−
185−# If true, an OpenSearch description file will be output, and all pages will
186−# contain a <link> tag referring to it. The value of this option must be the
187−# base URL from which the finished HTML is served.
188−#html_use_opensearch = ''
189−
190−# This is the file name suffix for HTML files (e.g. ".xhtml").
191−#html_file_suffix = None
192−
193−# Language to be used for generating the HTML full-text search index.
194−# Sphinx supports the following languages:
195−# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
196−# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
197−#html_search_language = 'en'
198
109
199−# A dictionary with options for the search language support, empty by default.
200−# Now only 'ja' uses this config value
201−#html_search_options = {'type': 'default'}
202
110
203−# The name of a javascript file (relative to the configuration directory) that
111+# -- Options for HTMLHelp output ------------------------------------------
204−# implements a search results scorer. If empty, the default will be used.
205−#html_search_scorer = 'scorer.js'
206
112
207# Output file base name for HTML help builder.
113# Output file base name for HTML help builder.
208−htmlhelp_basename = 'servantdoc'
114+htmlhelp_basename = 'Servantdoc'
115+
209
116
210# -- Options for LaTeX output ---------------------------------------------
117# -- Options for LaTeX output ---------------------------------------------
211
118
212latex_elements = {
119latex_elements = {
213−# The paper size ('letterpaper' or 'a4paper').
120+ # The paper size ('letterpaper' or 'a4paper').
121+ #
214−#'papersize': 'letterpaper',
122+ # 'papersize': 'letterpaper',
215
123
216−# The font size ('10pt', '11pt' or '12pt').
124+ # The font size ('10pt', '11pt' or '12pt').
125+ #
217−#'pointsize': '10pt',
126+ # 'pointsize': '10pt',
218
127
219−# Additional stuff for the LaTeX preamble.
128+ # Additional stuff for the LaTeX preamble.
129+ #
220−#'preamble': '',
130+ # 'preamble': '',
221
131
222−# Latex figure (float) alignment
132+ # Latex figure (float) alignment
133+ #
223−#'figure_align': 'htbp',
134+ # 'figure_align': 'htbp',
224}
135}
225
136
226# Grouping the document tree into LaTeX files. List of tuples
137# Grouping the document tree into LaTeX files. List of tuples
227# (source start file, target name, title,
138# (source start file, target name, title,
228# author, documentclass [howto, manual, or own class]).
139# author, documentclass [howto, manual, or own class]).
229latex_documents = [
140latex_documents = [
230− (master_doc, 'servant.tex', u'servant Documentation',
141+ (master_doc, 'Servant.tex', u'Servant Documentation',
231 u'Servant Contributors', 'manual'),
142 u'Servant Contributors', 'manual'),
232]
143]
233
144
234−# The name of an image file (relative to this directory) to place at the top of
235−# the title page.
236−#latex_logo = None
237−
238−# For "manual" documents, if this is true, then toplevel headings are parts,
239−# not chapters.
240−#latex_use_parts = False
241−
242−# If true, show page references after internal links.
243−#latex_show_pagerefs = False
244−
245−# If true, show URL addresses after external links.
246−#latex_show_urls = False
247−
248−# Documents to append as an appendix to all manuals.
249−#latex_appendices = []
250−
251−# If false, no module index is generated.
252−#latex_domain_indices = True
253−
254
145
255# -- Options for manual page output ---------------------------------------
146# -- Options for manual page output ---------------------------------------
256
147
257# One entry per manual page. List of tuples
148# One entry per manual page. List of tuples
258# (source start file, name, description, authors, manual section).
149# (source start file, name, description, authors, manual section).
259man_pages = [
150man_pages = [
260− (master_doc, 'servant', u'servant Documentation',
151+ (master_doc, 'servant', u'Servant Documentation',
261 [author], 1)
152 [author], 1)
262]
153]
263
154
264−# If true, show URL addresses after external links.
265−#man_show_urls = False
266−
267
155
268# -- Options for Texinfo output -------------------------------------------
156# -- Options for Texinfo output -------------------------------------------
269
157
@@ -271,24 +159,15 @@ man_pages = [
271# (source start file, target name, title, author,
159# (source start file, target name, title, author,
272# dir menu entry, description, category)
160# dir menu entry, description, category)
273texinfo_documents = [
161texinfo_documents = [
274− (master_doc, 'servant', u'servant Documentation',
162+ (master_doc, 'Servant', u'Servant Documentation',
275− author, 'servant', 'One line description of project.',
163+ author, 'Servant', 'One line description of project.',
276− 'Miscellaneous'),
164+ 'Miscellaneous'),
277]
165]
278
166
279−# Documents to append as an appendix to all manuals.
167+# -- Markdown -------------------------------------------------------------
280−#texinfo_appendices = []
281−
282−# If false, no module index is generated.
283−#texinfo_domain_indices = True
284−
285−# How to display URL addresses: 'footnote', 'no', or 'inline'.
286−#texinfo_show_urls = 'footnote'
287−
288−# If true, do not generate a @detailmenu in the "Top" node's menu.
289−#texinfo_no_detailmenu = False
290
168
291source_parsers = {
169source_parsers = {
292 '.md': CommonMarkParser,
170 '.md': CommonMarkParser,
293 '.lhs': CommonMarkParser,
171 '.lhs': CommonMarkParser,
294}
172}
173+
doc/cookbook/basic-auth/basic-auth.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-basic-auth
19executable cookbook-basic-auth
14 main-is: BasicAuth.lhs
20 main-is: BasicAuth.lhs
doc/cookbook/db-postgres-pool/db-postgres-pool.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-db-postgres-pool
19executable cookbook-db-postgres-pool
14 main-is: PostgresPool.lhs
20 main-is: PostgresPool.lhs
doc/cookbook/db-sqlite-simple/db-sqlite-simple.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-db-sqlite-simple
19executable cookbook-db-sqlite-simple
14 main-is: DBConnection.lhs
20 main-is: DBConnection.lhs
doc/cookbook/file-upload/file-upload.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-file-upload
19executable cookbook-file-upload
14 main-is: FileUpload.lhs
20 main-is: FileUpload.lhs
doc/cookbook/generic/Generic.lhsnew file+106
@@ -0,0 +1,106 @@
1+# Using generics
2+
3+```haskell
4+{-# LANGUAGE DataKinds #-}
5+{-# LANGUAGE DeriveGeneric #-}
6+{-# LANGUAGE RankNTypes #-}
7+{-# LANGUAGE TypeOperators #-}
8+module Main (main, api, getLink, routesLinks, cliGet) where
9+
10+import Control.Exception (throwIO)
11+import Data.Proxy (Proxy (..))
12+import Network.Wai.Handler.Warp (run)
13+import System.Environment (getArgs)
14+
15+import Servant
16+import Servant.Client
17+
18+import Servant.API.Generic
19+import Servant.Client.Generic
20+import Servant.Server.Generic
21+```
22+
23+The usage is simple, if you only need a collection of routes.
24+First you define a record with field types prefixed by a parameter `route`:
25+
26+```haskell
27+data Routes route = Routes
28+ { _get :: route :- Capture "id" Int :> Get '[JSON] String
29+ , _put :: route :- ReqBody '[JSON] Int :> Put '[JSON] Bool
30+ }
31+ deriving (Generic)
32+```
33+
34+Then we'll use this data type to define API, links, server and client.
35+
36+## API
37+
38+You can get a `Proxy` of the API using `genericApi`:
39+
40+```haskell
41+api :: Proxy (ToServantApi Routes)
42+api = genericApi (Proxy :: Proxy Routes)
43+```
44+
45+It's recommented to use `genericApi` function, as then you'll get
46+better error message, for example if you forget to `derive Generic`.
47+
48+## Links
49+
50+The clear advantage of record-based generics approach, is that
51+we can get safe links very conviently. We don't need to define endpoint types,
52+as field accessors work as proxies:
53+
54+```haskell
55+getLink :: Int -> Link
56+getLink = fieldLink _get
57+```
58+
59+We can also get all links at once, as a record:
60+
61+```haskell
62+routesLinks :: Routes (AsLink Link)
63+routesLinks = allFieldLinks
64+```
65+
66+## Client
67+
68+Even more power starts to show when we generate a record of client functions.
69+Here we use `genericClientHoist` function, which let us simultaneously
70+hoist the monad, in this case from `ClientM` to `IO`.
71+
72+```haskell
73+cliRoutes :: Routes (AsClientT IO)
74+cliRoutes = genericClientHoist
75+ (\x -> runClientM x env >>= either throwIO return)
76+ where
77+ env = error "undefined environment"
78+
79+cliGet :: Int -> IO String
80+cliGet = _get cliRoutes
81+```
82+
83+## Server
84+
85+Finally, probably the most handy usage: we can convert record of handlers into
86+the server implementation:
87+
88+```haskell
89+record :: Routes AsServer
90+record = Routes
91+ { _get = return . show
92+ , _put = return . odd
93+ }
94+
95+app :: Application
96+app = genericServe record
97+
98+main :: IO ()
99+main = do
100+ args <- getArgs
101+ case args of
102+ ("run":_) -> do
103+ putStrLn "Starting cookbook-generic at http://localhost:8000"
104+ run 8000 app
105+ _ -> putStrLn "To run, pass 'run' argument: cabal new-run cookbook-generic run"
106+```
doc/cookbook/generic/generic.cabalnew file+31
@@ -0,0 +1,31 @@
1+name: cookbook-generic
2+version: 0.1
3+synopsis: Using custom monad to pass a state between handlers
4+homepage: http://haskell-servant.readthedocs.org/
5+license: BSD3
6+license-file: ../../../servant/LICENSE
7+author: Servant Contributors
8+maintainer: haskell-servant-maintainers@googlegroups.com
9+build-type: Simple
10+cabal-version: >=1.10
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
18+
19+executable cookbook-using-custom-monad
20+ main-is: Generic.lhs
21+ build-depends: base == 4.*
22+ , servant
23+ , servant-client
24+ , servant-client-core
25+ , servant-server
26+ , base-compat
27+ , warp >= 3.2
28+ , transformers >= 0.3
29+ default-language: Haskell2010
30+ ghc-options: -Wall -pgmL markdown-unlit
31+ build-tool-depends: markdown-unlit:markdown-unlit >= 0.4
doc/cookbook/https/https.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-https
19executable cookbook-https
14 main-is: Https.lhs
20 main-is: Https.lhs
doc/cookbook/index.rst+1
@@ -18,6 +18,7 @@ you name it!
18 :maxdepth: 1
18 :maxdepth: 1
19
19
20 structuring-apis/StructuringApis.lhs
20 structuring-apis/StructuringApis.lhs
21+ generic/Generic.lhs
21 https/Https.lhs
22 https/Https.lhs
22 db-sqlite-simple/DBConnection.lhs
23 db-sqlite-simple/DBConnection.lhs
23 db-postgres-pool/PostgresPool.lhs
24 db-postgres-pool/PostgresPool.lhs
doc/cookbook/jwt-and-basic-auth/jwt-and-basic-auth.cabal+7−1
@@ -11,7 +11,13 @@ maintainer: haskell-servant-maintainers@googlegroups.com
11category: Servant
11category: Servant
12build-type: Simple
12build-type: Simple
13cabal-version: >=1.10
13cabal-version: >=1.10
14−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
14+tested-with:
15+ GHC==7.8.4
16+ GHC==7.10.3
17+ GHC==8.0.2
18+ GHC==8.2.2
19+ GHC==8.4.4
20+ GHC==8.6.1
15
21
16executable cookbook-jwt-and-basic-auth
22executable cookbook-jwt-and-basic-auth
17 if !impl(ghc >= 7.10)
23 if !impl(ghc >= 7.10)
doc/cookbook/pagination/pagination.cabal+8−2
@@ -11,7 +11,13 @@ cabal-version: >=1.10
11extra-source-files:
11extra-source-files:
12 Pagination.lhs
12 Pagination.lhs
13 dummy/Pagination.lhs
13 dummy/Pagination.lhs
14−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
14+tested-with:
15+ GHC==7.8.4
16+ GHC==7.10.3
17+ GHC==8.0.2
18+ GHC==8.2.2
19+ GHC==8.4.4
20+ GHC==8.6.1
15
21
16executable cookbook-pagination
22executable cookbook-pagination
17 main-is: Pagination.lhs
23 main-is: Pagination.lhs
@@ -21,7 +27,7 @@ executable cookbook-pagination
21
27
22 if impl(ghc >= 8.0)
28 if impl(ghc >= 8.0)
23 hs-source-dirs: .
29 hs-source-dirs: .
24− build-depends: base >= 4.8 && <4.12
30+ build-depends: base >= 4.8
25 , aeson
31 , aeson
26 , servant
32 , servant
27 , servant-server
33 , servant-server
doc/cookbook/structuring-apis/structuring-apis.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-structuring-apis
19executable cookbook-structuring-apis
14 main-is: StructuringApis.lhs
20 main-is: StructuringApis.lhs
doc/cookbook/using-custom-monad/using-custom-monad.cabal+7−1
@@ -8,7 +8,13 @@ author: Servant Contributors
8maintainer: haskell-servant-maintainers@googlegroups.com
8maintainer: haskell-servant-maintainers@googlegroups.com
9build-type: Simple
9build-type: Simple
10cabal-version: >=1.10
10cabal-version: >=1.10
11−tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
11+tested-with:
12+ GHC==7.8.4
13+ GHC==7.10.3
14+ GHC==8.0.2
15+ GHC==8.2.2
16+ GHC==8.4.4
17+ GHC==8.6.1
12
18
13executable cookbook-using-custom-monad
19executable cookbook-using-custom-monad
14 main-is: UsingCustomMonad.lhs
20 main-is: UsingCustomMonad.lhs
doc/index.rst+11−9
@@ -3,22 +3,24 @@ servant – A Type-Level Web DSL
3
3
4.. image:: https://raw.githubusercontent.com/haskell-servant/servant/master/servant.png
4.. image:: https://raw.githubusercontent.com/haskell-servant/servant/master/servant.png
5
5
6−**servant** is a set of packages for declaring web APIs at the type-level and
6+**servant** is a set of Haskell libraries for writing *type-safe* web
7−then using those API specifications to:
7+applications but also *deriving* clients (in Haskell and other languages) or
8+generating documentation for them, and more.
8
9
9−- write servers (this part of **servant** can be considered a web framework),
10+This is achieved by taking as input a description of the web API
10−- obtain client functions (in haskell),
11+as a Haskell type. Servant is then able to check that your server-side request
11−- generate client functions for other programming languages,
12+handlers indeed implement your web API faithfully, or to automatically derive
12−- generate documentation for your web applications
13+Haskell functions that can hit a web application that implements this API,
13−- and more...
14+generate a Swagger description or code for client functions in some other
15+languages directly.
14
16
15−All in a type-safe manner.
17+If you would like to learn more, click the tutorial link below.
16
18
17.. toctree::
19.. toctree::
18 :maxdepth: 2
20 :maxdepth: 2
19
21
20− introduction.rst
21 tutorial/index.rst
22 tutorial/index.rst
22 cookbook/index.rst
23 cookbook/index.rst
23 examples.md
24 examples.md
24 links.rst
25 links.rst
26+ principles.rst
doc/make.batnew file+36
@@ -0,0 +1,36 @@
1+@ECHO OFF
2+
3+pushd %~dp0
4+
5+REM Command file for Sphinx documentation
6+
7+if "%SPHINXBUILD%" == "" (
8+ set SPHINXBUILD=sphinx-build
9+)
10+set SOURCEDIR=.
11+set BUILDDIR=_build
12+set SPHINXPROJ=Servant
13+
14+if "%1" == "" goto help
15+
16+%SPHINXBUILD% >NUL 2>NUL
17+if errorlevel 9009 (
18+ echo.
19+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
20+ echo.installed, then set the SPHINXBUILD environment variable to point
21+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
22+ echo.may add the Sphinx directory to PATH.
23+ echo.
24+ echo.If you don't have Sphinx installed, grab it from
25+ echo.http://sphinx-doc.org/
26+ exit /b 1
27+)
28+
29+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30+goto end
31+
32+:help
33+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34+
35+:end
36+popd
doc/introduction.rst → doc/principles.rstrenamed+2−2
@@ -1,5 +1,5 @@
1−Introduction
1+Principles
2−------------
2+----------
3
3
4**servant** has the following guiding principles:
4**servant** has the following guiding principles:
5
5
doc/req.txtnew file+25
@@ -0,0 +1,25 @@
1+alabaster==0.7.11
2+argh==0.26.2
3+Babel==2.6.0
4+backports-abc==0.5
5+backports.ssl-match-hostname==3.5.0.1
6+certifi==2018.4.16
7+CommonMark==0.7.5
8+docutils==0.14
9+Jinja2==2.10
10+livereload==2.5.2
11+MarkupSafe==1.0
12+pathtools==0.1.2
13+Pygments==2.2.0
14+pytz==2018.5
15+PyYAML==3.13
16+recommonmark==0.4.0
17+singledispatch==3.4.0.3
18+six==1.11.0
19+snowballstemmer==1.2.1
20+Sphinx==1.6.5
21+sphinx-autobuild==0.7.1
22+sphinx_rtd_theme>=0.4.0
23+tornado==5.0.2
24+watchdog==0.8.3
25+wheel==0.31.1
doc/requirements.txt+2−24
@@ -1,25 +1,3 @@
1−alabaster==0.7.7
2−argh==0.26.1
3−Babel==2.2.0
4−backports-abc==0.4
5−backports.ssl-match-hostname==3.5.0.1
6−certifi==2015.11.20.1
7−CommonMark==0.5.4
8−docutils==0.12
9−Jinja2==2.8
10−livereload==2.4.1
11−MarkupSafe==0.23
12−pathtools==0.1.2
13−Pygments==2.2.0
14−pytz==2015.7
15−PyYAML==3.11
16recommonmark==0.4.0
1recommonmark==0.4.0
17−singledispatch==3.4.0.3
18−six==1.10.0
19−snowballstemmer==1.2.1
20−Sphinx==1.3.6
2+Sphinx==1.7.5
21−sphinx-autobuild==0.5.2
3+sphinx_rtd_theme>=0.4.0
22−sphinx-rtd-theme==0.1.9
23−tornado==4.3
24−watchdog==0.8.3
25−wheel==0.26.0
doc/setup.pynew file+11
@@ -0,0 +1,11 @@
1+from setuptools import setup
2+
3+setup(name='servant-rtd',
4+ version='0.0.1',
5+ description='Documentation for the haskell-servant platform',
6+ url='https://github.com/haskell-servant/servant',
7+ author='Servant Contributors',
8+ author_email='haskell-servant-maintainers@googlegroups.com',
9+ license='BSD3',
10+ zip_safe=False)
11+
doc/tutorial/Javascript.lhs+1−2
@@ -477,7 +477,7 @@ data AngularOptions = AngularOptions
477 }
477 }
478```
478```
479
479
480−# Custom function name builder
480+## Custom function name builder
481
481
482Servant comes with three name builders included:
482Servant comes with three name builders included:
483
483
@@ -518,4 +518,3 @@ var get_books = function(q, onSuccess, onError)
518}
518}
519
519
520```
520```
521−
doc/tutorial/index.rst+21−2
@@ -3,9 +3,28 @@ Tutorial
3
3
4This is an introductory tutorial to **servant**. Whilst browsing is fine, it makes more sense if you read the sections in order, or at least read the first section before anything else.
4This is an introductory tutorial to **servant**. Whilst browsing is fine, it makes more sense if you read the sections in order, or at least read the first section before anything else.
5
5
6−(Any comments, issues or feedback about the tutorial can be submitted
6+Any comments, issues or feedback about the tutorial can be submitted
7−to `servant's issue tracker <http://github.com/haskell-servant/servant/issues>`_.)
7+to `servant's issue tracker <http://github.com/haskell-servant/servant/issues>`_.
8
8
9+In fact, the whole tutorial is a `cabal <https://cabal.readthedocs.io/en/latest/>`_
10+project and can be built and played with locally as follows:
11+
12+.. code-block:: bash
13+
14+ $ git clone https://github.com/haskell-servant/servant.git
15+ $ cd servant
16+ # build
17+ $ cabal new-build tutorial
18+ # load in ghci to play with it
19+ $ cabal new-repl tutorial
20+
21+The code can be found in the `*.lhs` files under `doc/tutorial/` in the
22+repository. Feel free to edit it while you're reading this documentation and
23+see the effect of your changes.
24+
25+`Nix <https://nixos.org/nix/>`_ users should feel free to take a look at
26+the `nix/shell.nix` file in the repository and use it to provision a suitable
27+environment to build and run the examples.
9
28
10.. toctree::
29.. toctree::
11 :maxdepth: 1
30 :maxdepth: 1
doc/tutorial/tutorial.cabal+5−4
@@ -17,7 +17,8 @@ tested-with:
17 GHC==7.10.3
17 GHC==7.10.3
18 GHC==8.0.2
18 GHC==8.0.2
19 GHC==8.2.2
19 GHC==8.2.2
20− GHC==8.4.3
20+ GHC==8.4.4
21+ GHC==8.6.1
21extra-source-files:
22extra-source-files:
22 static/index.html
23 static/index.html
23 static/ui.js
24 static/ui.js
@@ -35,7 +36,7 @@ library
35 -- Packages `servant` depends on.
36 -- Packages `servant` depends on.
36 -- We don't need to specify bounds here as this package is never released.
37 -- We don't need to specify bounds here as this package is never released.
37 build-depends:
38 build-depends:
38− base >= 4.7 && <4.12
39+ base >= 4.7 && <4.13
39 , aeson
40 , aeson
40 , aeson-compat
41 , aeson-compat
41 , attoparsec
42 , attoparsec
@@ -75,8 +76,8 @@ library
75 , time >= 1.4.2 && < 1.9
76 , time >= 1.4.2 && < 1.9
76
77
77 -- For legacy tools, we need to specify build-depends too
78 -- For legacy tools, we need to specify build-depends too
78− build-depends: markdown-unlit >= 0.4.1 && <0.5
79+ build-depends: markdown-unlit >= 0.5.0 && <0.6
79− build-tool-depends: markdown-unlit:markdown-unlit >= 0.4.1 && <0.5
80+ build-tool-depends: markdown-unlit:markdown-unlit >= 0.5.0 && <0.6
80
81
81test-suite spec
82test-suite spec
82 type: exitcode-stdio-1.0
83 type: exitcode-stdio-1.0
servant-client-core/CHANGELOG.md+50−2
@@ -1,13 +1,61 @@
1[The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant-client-core/CHANGELOG.md)
1[The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant-client-core/CHANGELOG.md)
2[Changelog for `servant` package contains significant entries for all core packages.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
2[Changelog for `servant` package contains significant entries for all core packages.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
3
3
4+0.14.1
5+------
6+
7+- Merge in `servant-generic` (by [Patrick Chilton](https://github.com/chpatrick))
8+ into `servant` (`Servant.API.Generic`),
9+ `servant-client-code` (`Servant.Client.Generic`)
10+ and `servant-server` (`Servant.Server.Generic`).
11+
40.14
120.14
5----
13----
6
14
7−- Add a `hoistClientMonad` method to the `HasClient` typeclass, for
15+- `Stream` takes a status code argument
16+
17+ ```diff
18+ -Stream method framing ctype a
19+ +Stream method status framing ctype a
20+ ```
21+
22+ ([#966](https://github.com/haskell-servant/servant/pull/966)
23+ [#972](https://github.com/haskell-servant/servant/pull/972))
24+
25+- `ToStreamGenerator` definition changed, so it's possible to write an instance
26+ for conduits.
27+
28+ ```diff
29+ -class ToStreamGenerator f a where
30+ - toStreamGenerator :: f a -> StreamGenerator a
31+ +class ToStreamGenerator a b | a -> b where
32+ + toStreamGenerator :: a -> StreamGenerator b
33+ ```
34+
35+ ([#959](https://github.com/haskell-servant/servant/pull/959))
36+
37+- Added `NoFraming` streaming strategy
38+ ([#959](https://github.com/haskell-servant/servant/pull/959))
39+
40+- *servant-client-core* Free `Client` implementation.
41+ Useful for testing `HasClient` instances.
42+ ([#920](https://github.com/haskell-servant/servant/pull/920))
43+
44+- *servant-client-core* Add `hoistClient` to `HasClient`.
45+ Just like `hoistServer` allows us to change the monad in which request handlers
46+ of a web application live in, we also have `hoistClient` for changing the monad
8− changing the monad in which client functions run.
47+ in which *client functions* live.
48+ Read [tutorial section for more information](https://haskell-servant.readthedocs.io/en/release-0.14/tutorial/Client.html#changing-the-monad-the-client-functions-live-in).
9 ([#936](https://github.com/haskell-servant/servant/pull/936))
49 ([#936](https://github.com/haskell-servant/servant/pull/936))
10
50
51+ iF you have own combinators, you'll need to define a new method of
52+ `HasClient` class, for example:
53+
54+ ```haskell
55+ type Client m (MyCombinator :> api) = MyValue :> Client m api
56+ hoistClientMonad pm _ nt cl = hoistClientMonad pm (Proxy :: Proxy api) nt . cl
57+ ```
58+
110.13.0.1
590.13.0.1
12--------
60--------
13
61
servant-client-core/servant-client-core.cabal+23−19
@@ -1,9 +1,13 @@
1name: servant-client-core
1name: servant-client-core
2−version: 0.14
2+version: 0.14.1
3+x-revision: 2
4+
3synopsis: Core functionality and class for client function generation for servant APIs
5synopsis: Core functionality and class for client function generation for servant APIs
6+category: Web, Servant
4description:
7description:
5 This library provides backend-agnostic generation of client functions. For
8 This library provides backend-agnostic generation of client functions. For
6 more information, see the README.
9 more information, see the README.
10+
7license: BSD3
11license: BSD3
8license-file: LICENSE
12license-file: LICENSE
9author: Servant Contributors
13author: Servant Contributors
@@ -12,7 +16,6 @@ homepage: http://haskell-servant.readthedocs.org/
12bug-reports: http://github.com/haskell-servant/servant/issues
16bug-reports: http://github.com/haskell-servant/servant/issues
13cabal-version: >=1.10
17cabal-version: >=1.10
14copyright: 2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors
18copyright: 2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors
15−category: Web
16build-type: Simple
19build-type: Simple
17extra-source-files:
20extra-source-files:
18 include/*.h
21 include/*.h
@@ -23,7 +26,8 @@ tested-with:
23 GHC==7.10.3
26 GHC==7.10.3
24 GHC==8.0.2
27 GHC==8.0.2
25 GHC==8.2.2
28 GHC==8.2.2
26− GHC==8.4.3
29+ GHC==8.4.4
30+ GHC==8.6.1
27
31
28source-repository head
32source-repository head
29 type: git
33 type: git
@@ -33,6 +37,7 @@ library
33 exposed-modules:
37 exposed-modules:
34 Servant.Client.Core
38 Servant.Client.Core
35 Servant.Client.Free
39 Servant.Client.Free
40+ Servant.Client.Generic
36 Servant.Client.Core.Reexport
41 Servant.Client.Core.Reexport
37 Servant.Client.Core.Internal.Auth
42 Servant.Client.Core.Internal.Auth
38 Servant.Client.Core.Internal.BaseUrl
43 Servant.Client.Core.Internal.BaseUrl
@@ -48,33 +53,32 @@ library
48 --
53 --
49 -- note: mtl lower bound is so low because of GHC-7.8
54 -- note: mtl lower bound is so low because of GHC-7.8
50 build-depends:
55 build-depends:
51− base >= 4.7 && < 4.12
56+ base >= 4.7 && < 4.13
52 , bytestring >= 0.10.4.0 && < 0.11
57 , bytestring >= 0.10.4.0 && < 0.11
53− , containers >= 0.5.5.1 && < 0.6
58+ , containers >= 0.5.5.1 && < 0.7
54− , mtl >= 2.1 && < 2.3
55 , text >= 1.2.3.0 && < 1.3
59 , text >= 1.2.3.0 && < 1.3
56
60
57 if !impl(ghc >= 8.0)
61 if !impl(ghc >= 8.0)
58 build-depends:
62 build-depends:
59− semigroups >=0.18.3 && <0.19
63+ semigroups >=0.18.4 && <0.19
60
64
61 -- Servant dependencies
65 -- Servant dependencies
62 build-depends:
66 build-depends:
63− servant == 0.14.*
67+ servant >= 0.14.1 && <0.15
64
68
65 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
69 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
66 -- Here can be exceptions if we really need features from the newer versions.
70 -- Here can be exceptions if we really need features from the newer versions.
67 build-depends:
71 build-depends:
68− base-compat >= 0.9.3 && < 0.11
72+ base-compat >= 0.10.1 && < 0.11
69 , base64-bytestring >= 1.0.0.1 && < 1.1
73 , base64-bytestring >= 1.0.0.1 && < 1.1
70− , exceptions >= 0.8.3 && < 0.11
74+ , exceptions >= 0.10.0 && < 0.11
71− , free >= 5.0.1 && < 5.1
75+ , free >= 5.0.2 && < 5.2
72− , generics-sop >= 0.3.1.0 && < 0.4
76+ , generics-sop >= 0.3.2.0 && < 0.5
73− , http-api-data >= 0.3.7.1 && < 0.4
77+ , http-api-data >= 0.3.8.1 && < 0.4
74− , http-media >= 0.7.1.1 && < 0.8
78+ , http-media >= 0.7.1.2 && < 0.8
75− , http-types >= 0.12 && < 0.13
79+ , http-types >= 0.12.1 && < 0.13
76 , network-uri >= 2.6.1.0 && < 2.7
80 , network-uri >= 2.6.1.0 && < 2.7
77− , safe >= 0.3.15 && < 0.4
81+ , safe >= 0.3.17 && < 0.4
78
82
79 hs-source-dirs: src
83 hs-source-dirs: src
80 default-language: Haskell2010
84 default-language: Haskell2010
@@ -99,8 +103,8 @@ test-suite spec
99 -- Additonal dependencies
103 -- Additonal dependencies
100 build-depends:
104 build-depends:
101 deepseq >= 1.3.0.2 && <1.5
105 deepseq >= 1.3.0.2 && <1.5
102− , hspec >= 2.4.4 && <2.6
106+ , hspec >= 2.4.1 && <2.6
103− , QuickCheck >= 2.10.1 && < 2.12
107+ , QuickCheck >= 2.11.3 && < 2.13
104
108
105 build-tool-depends:
109 build-tool-depends:
106− hspec-discover:hspec-discover >= 2.4.4 && <2.6
110+ hspec-discover:hspec-discover >= 2.5.1 && <2.6
servant-client-core/src/Servant/Client/Generic.hsnew file+51
@@ -0,0 +1,51 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE KindSignatures #-}
4+{-# LANGUAGE RankNTypes #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE TypeFamilies #-}
7+module Servant.Client.Generic (
8+ AsClientT,
9+ genericClient,
10+ genericClientHoist,
11+ ) where
12+
13+import Data.Proxy
14+ (Proxy (..))
15+
16+import Servant.API.Generic
17+import Servant.Client.Core
18+
19+-- | A type that specifies that an API reocrd contains a client implementation.
20+data AsClientT (m :: * -> *)
21+instance GenericMode (AsClientT m) where
22+ type AsClientT m :- api = Client m api
23+
24+-- | Generate a record of client functions.
25+genericClient
26+ :: forall routes m.
27+ ( HasClient m (ToServantApi routes)
28+ , GenericServant routes (AsClientT m)
29+ , Client m (ToServantApi routes) ~ ToServant routes (AsClientT m)
30+ )
31+ => routes (AsClientT m)
32+genericClient
33+ = fromServant
34+ $ clientIn (Proxy :: Proxy (ToServantApi routes)) (Proxy :: Proxy m)
35+
36+-- | 'genericClient' but with 'hoistClientMonad' in between.
37+genericClientHoist
38+ :: forall routes m n.
39+ ( HasClient m (ToServantApi routes)
40+ , GenericServant routes (AsClientT n)
41+ , Client n (ToServantApi routes) ~ ToServant routes (AsClientT n)
42+ )
43+ => (forall x. m x -> n x) -- ^ natural transformation
44+ -> routes (AsClientT n)
45+genericClientHoist nt
46+ = fromServant
47+ $ hoistClientMonad m api nt
48+ $ clientIn api m
49+ where
50+ m = Proxy :: Proxy m
51+ api = Proxy :: Proxy (ToServantApi routes)
servant-client-ghcjs/servant-client-ghcjs.cabal+3−3
@@ -31,10 +31,10 @@ library
31 Servant.Client.Ghcjs
31 Servant.Client.Ghcjs
32 Servant.Client.Internal.XhrClient
32 Servant.Client.Internal.XhrClient
33 build-depends:
33 build-depends:
34− base >= 4.7 && < 4.12
34+ base >= 4.7 && < 4.13
35 , bytestring >= 0.10 && < 0.11
35 , bytestring >= 0.10 && < 0.11
36 , case-insensitive >= 1.2.0.0 && < 1.3.0.0
36 , case-insensitive >= 1.2.0.0 && < 1.3.0.0
37− , containers >= 0.5 && < 0.6
37+ , containers >= 0.5 && < 0.7
38 , exceptions >= 0.8 && < 0.11
38 , exceptions >= 0.8 && < 0.11
39 , ghcjs-base >= 0.2.0.0 && < 0.3.0.0
39 , ghcjs-base >= 0.2.0.0 && < 0.3.0.0
40 , ghcjs-prim >= 0.1.0.0 && < 0.2.0.0
40 , ghcjs-prim >= 0.1.0.0 && < 0.2.0.0
@@ -42,7 +42,7 @@ library
42 , http-types >= 0.12 && < 0.13
42 , http-types >= 0.12 && < 0.13
43 , monad-control >= 1.0.0.4 && < 1.1
43 , monad-control >= 1.0.0.4 && < 1.1
44 , mtl >= 2.1 && < 2.3
44 , mtl >= 2.1 && < 2.3
45− , semigroupoids >= 4.3 && < 5.3
45+ , semigroupoids >= 4.3 && < 5.4
46 , servant-client-core == 0.14.*
46 , servant-client-core == 0.14.*
47 , string-conversions >= 0.3 && < 0.5
47 , string-conversions >= 0.3 && < 0.5
48 , transformers >= 0.3 && < 0.6
48 , transformers >= 0.3 && < 0.6
servant-client/CHANGELOG.md+37−2
@@ -4,10 +4,45 @@
40.14
40.14
5----
5----
6
6
7−- Add `hoistClient` for changing the monad in which
7+- `Stream` takes a status code argument
8+
9+ ```diff
10+ -Stream method framing ctype a
11+ +Stream method status framing ctype a
12+ ```
13+
14+ ([#966](https://github.com/haskell-servant/servant/pull/966)
15+ [#972](https://github.com/haskell-servant/servant/pull/972))
16+
17+- `ToStreamGenerator` definition changed, so it's possible to write an instance
18+ for conduits.
19+
20+ ```diff
21+ -class ToStreamGenerator f a where
22+ - toStreamGenerator :: f a -> StreamGenerator a
23+ +class ToStreamGenerator a b | a -> b where
24+ + toStreamGenerator :: a -> StreamGenerator b
25+ ```
26+
27+ ([#959](https://github.com/haskell-servant/servant/pull/959))
28+
29+- Added `NoFraming` streaming strategy
30+ ([#959](https://github.com/haskell-servant/servant/pull/959))
31+
32+- *servant-client-core* Add `hoistClient` to `HasClient`.
33+ Just like `hoistServer` allows us to change the monad in which request handlers
34+ of a web application live in, we also have `hoistClient` for changing the monad
8− client functions run.
35+ in which *client functions* live.
36+ Read [tutorial section for more information](https://haskell-servant.readthedocs.io/en/release-0.14/tutorial/Client.html#changing-the-monad-the-client-functions-live-in).
9 ([#936](https://github.com/haskell-servant/servant/pull/936))
37 ([#936](https://github.com/haskell-servant/servant/pull/936))
10
38
39+- *servant-client* Add more constructors to `RequestBody`, including
40+ `RequestBodyStream`.
41+ *Note:* we are looking for http-library agnostic API,
42+ so the might change again soon.
43+ Tell us which constructors are useful for you!
44+ ([#913](https://github.com/haskell-servant/servant/pull/913))
45+
110.13.0.1
460.13.0.1
12--------
47--------
13
48
servant-client/servant-client.cabal+28−29
@@ -1,6 +1,9 @@
1name: servant-client
1name: servant-client
2version: 0.14
2version: 0.14
3+x-revision: 3
4+
3synopsis: automatical derivation of querying functions for servant webservices
5synopsis: automatical derivation of querying functions for servant webservices
6+category: Servant, Web
4description:
7description:
5 This library lets you derive automatically Haskell functions that
8 This library lets you derive automatically Haskell functions that
6 let you query each endpoint of a <http://hackage.haskell.org/package/servant servant> webservice.
9 let you query each endpoint of a <http://hackage.haskell.org/package/servant servant> webservice.
@@ -8,12 +11,12 @@ description:
8 See <http://haskell-servant.readthedocs.org/en/stable/tutorial/Client.html the client section of the tutorial>.
11 See <http://haskell-servant.readthedocs.org/en/stable/tutorial/Client.html the client section of the tutorial>.
9 .
12 .
10 <https://github.com/haskell-servant/servant/blob/master/servant-client/CHANGELOG.md CHANGELOG>
13 <https://github.com/haskell-servant/servant/blob/master/servant-client/CHANGELOG.md CHANGELOG>
14+
11license: BSD3
15license: BSD3
12license-file: LICENSE
16license-file: LICENSE
13author: Servant Contributors
17author: Servant Contributors
14maintainer: haskell-servant-maintainers@googlegroups.com
18maintainer: haskell-servant-maintainers@googlegroups.com
15copyright: 2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors
19copyright: 2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors
16−category: Servant, Web
17build-type: Simple
20build-type: Simple
18cabal-version: >=1.10
21cabal-version: >=1.10
19tested-with:
22tested-with:
@@ -21,7 +24,9 @@ tested-with:
21 GHC==7.10.3
24 GHC==7.10.3
22 GHC==8.0.2
25 GHC==8.0.2
23 GHC==8.2.2
26 GHC==8.2.2
24− GHC==8.4.3
27+ GHC==8.4.4
28+ GHC==8.6.1
29+
25homepage: http://haskell-servant.readthedocs.org/
30homepage: http://haskell-servant.readthedocs.org/
26Bug-reports: http://github.com/haskell-servant/servant/issues
31Bug-reports: http://github.com/haskell-servant/servant/issues
27extra-source-files:
32extra-source-files:
@@ -42,16 +47,16 @@ library
42 --
47 --
43 -- note: mtl lower bound is so low because of GHC-7.8
48 -- note: mtl lower bound is so low because of GHC-7.8
44 build-depends:
49 build-depends:
45− base >= 4.7 && < 4.12
50+ base >= 4.7 && < 4.13
46 , bytestring >= 0.10.4.0 && < 0.11
51 , bytestring >= 0.10.4.0 && < 0.11
47− , containers >= 0.5.5.1 && < 0.6
52+ , containers >= 0.5.5.1 && < 0.7
48 , mtl >= 2.1 && < 2.3
53 , mtl >= 2.1 && < 2.3
49 , text >= 1.2.3.0 && < 1.3
54 , text >= 1.2.3.0 && < 1.3
50 , time >= 1.4.2 && < 1.9
55 , time >= 1.4.2 && < 1.9
51 , transformers >= 0.3.0.0 && < 0.6
56 , transformers >= 0.3.0.0 && < 0.6
52
57
53 if !impl(ghc >= 8.0)
58 if !impl(ghc >= 8.0)
54− build-depends: semigroups >=0.18.3 && <0.19
59+ build-depends: semigroups >=0.18.4 && <0.19
55
60
56 -- Servant dependencies
61 -- Servant dependencies
57 build-depends:
62 build-depends:
@@ -60,19 +65,16 @@ library
60 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
65 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
61 -- Here can be exceptions if we really need features from the newer versions.
66 -- Here can be exceptions if we really need features from the newer versions.
62 build-depends:
67 build-depends:
63− aeson >= 1.2.3.0 && < 1.5
64− , base-compat >= 0.9.3 && < 0.11
68+ base-compat >= 0.10.1 && < 0.11
65− , attoparsec >= 0.13.2.0 && < 0.14
66− , http-client >= 0.5.7.1 && < 0.6
69+ , http-client >= 0.5.12 && < 0.6
67− , http-client-tls >= 0.3.5.1 && < 0.4
68− , http-media >= 0.7.1.1 && < 0.8
70+ , http-media >= 0.7.1.2 && < 0.8
69− , http-types >= 0.12 && < 0.13
71+ , http-types >= 0.12.1 && < 0.13
70− , exceptions >= 0.8.3 && < 0.11
72+ , exceptions >= 0.10.0 && < 0.11
71− , monad-control >= 1.0.0.4 && < 1.1
73+ , monad-control >= 1.0.2.3 && < 1.1
72− , semigroupoids >= 5.2.1 && < 5.3
74+ , semigroupoids >= 5.2.2 && < 5.4
73− , stm >= 2.4.4.1 && < 2.5
75+ , stm >= 2.4.5.0 && < 2.6
74− , transformers-base >= 0.4.4 && < 0.5
76+ , transformers-base >= 0.4.5.2 && < 0.5
75− , transformers-compat >= 0.5.1 && < 0.7
77+ , transformers-compat >= 0.6.2 && < 0.7
76
78
77 hs-source-dirs: src
79 hs-source-dirs: src
78 default-language: Haskell2010
80 default-language: Haskell2010
@@ -97,10 +99,8 @@ test-suite spec
97 , aeson
99 , aeson
98 , base-compat
100 , base-compat
99 , bytestring
101 , bytestring
100− , containers
101 , http-api-data
102 , http-api-data
102 , http-client
103 , http-client
103− , http-media
104 , http-types
104 , http-types
105 , mtl
105 , mtl
106 , servant-client
106 , servant-client
@@ -117,18 +117,16 @@ test-suite spec
117
117
118 -- Additonal dependencies
118 -- Additonal dependencies
119 build-depends:
119 build-depends:
120− deepseq >= 1.3.0.2 && < 1.5
121− , generics-sop >= 0.3.1.0 && < 0.4
120+ generics-sop >= 0.3.2.0 && < 0.5
122− , hspec >= 2.4.4 && < 2.6
121+ , hspec >= 2.5.1 && < 2.6
123 , HUnit >= 1.6 && < 1.7
122 , HUnit >= 1.6 && < 1.7
124− , random-bytestring >= 0.1 && < 0.2
125− , network >= 2.6.3.2 && < 2.8
123+ , network >= 2.6.3.2 && < 2.9
126− , QuickCheck >= 2.10.1 && < 2.12
124+ , QuickCheck >= 2.10.1 && < 2.13
127− , servant == 0.13.*
125+ , servant == 0.14.*
128− , servant-server == 0.13.*
126+ , servant-server == 0.14.*
129
127
130 build-tool-depends:
128 build-tool-depends:
131− hspec-discover:hspec-discover >= 2.4.4 && < 2.6
129+ hspec-discover:hspec-discover >= 2.5.1 && < 2.6
132
130
133test-suite readme
131test-suite readme
134 type: exitcode-stdio-1.0
132 type: exitcode-stdio-1.0
@@ -136,3 +134,4 @@ test-suite readme
136 build-depends: base, servant, http-client, text, servant-client, markdown-unlit
134 build-depends: base, servant, http-client, text, servant-client, markdown-unlit
137 build-tool-depends: markdown-unlit:markdown-unlit
135 build-tool-depends: markdown-unlit:markdown-unlit
138 ghc-options: -pgmL markdown-unlit
136 ghc-options: -pgmL markdown-unlit
137+ default-language: Haskell2010
servant-client/test/Servant/StreamSpec.hs+2
@@ -130,6 +130,7 @@ streamSpec = beforeAll (CS.startWaiApp server) $ afterAll CS.endWaiApp $ do
130 jrb = Just (Right bob)
130 jrb = Just (Right bob)
131 runResultStream res `shouldReturn` (jra, jrb, jra, Nothing)
131 runResultStream res `shouldReturn` (jra, jrb, jra, Nothing)
132
132
133+{-
133 it "streams in constant memory" $ \(_, baseUrl) -> do
134 it "streams in constant memory" $ \(_, baseUrl) -> do
134 Right (ResultStream res) <- runClient getGetALot baseUrl
135 Right (ResultStream res) <- runClient getGetALot baseUrl
135 let consumeNChunks n = replicateM_ n (res void)
136 let consumeNChunks n = replicateM_ n (res void)
@@ -140,6 +141,7 @@ streamSpec = beforeAll (CS.startWaiApp server) $ afterAll CS.endWaiApp $ do
140 memUsed <- currentBytesUsed <$> getGCStats
141 memUsed <- currentBytesUsed <$> getGCStats
141#endif
142#endif
142 memUsed `shouldSatisfy` (< megabytes 22)
143 memUsed `shouldSatisfy` (< megabytes 22)
144+-}
143
145
144megabytes :: Num a => a -> a
146megabytes :: Num a => a -> a
145megabytes n = n * (1000 ^ (2 :: Int))
147megabytes n = n * (1000 ^ (2 :: Int))
servant-docs/servant-docs.cabal+10−6
@@ -1,19 +1,21 @@
1name: servant-docs
1name: servant-docs
2version: 0.11.2
2version: 0.11.2
3−x-revision: 4
3+x-revision: 6
4+
4synopsis: generate API docs for your servant webservice
5synopsis: generate API docs for your servant webservice
6+category: Servant, Web
5description:
7description:
6 Library for generating API docs from a servant API definition.
8 Library for generating API docs from a servant API definition.
7 .
9 .
8 Runnable example <https://github.com/haskell-servant/servant/blob/master/servant-docs/example/greet.hs here>.
10 Runnable example <https://github.com/haskell-servant/servant/blob/master/servant-docs/example/greet.hs here>.
9 .
11 .
10 <https://github.com/haskell-servant/servant/blob/master/servant-docs/CHANGELOG.md CHANGELOG>
12 <https://github.com/haskell-servant/servant/blob/master/servant-docs/CHANGELOG.md CHANGELOG>
13+
11license: BSD3
14license: BSD3
12license-file: LICENSE
15license-file: LICENSE
13author: Servant Contributors
16author: Servant Contributors
14maintainer: haskell-servant-maintainers@googlegroups.com
17maintainer: haskell-servant-maintainers@googlegroups.com
15copyright: 2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
18copyright: 2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
16−category: Servant, Web
17build-type: Simple
19build-type: Simple
18cabal-version: >=1.10
20cabal-version: >=1.10
19tested-with:
21tested-with:
@@ -21,7 +23,9 @@ tested-with:
21 GHC==7.10.3
23 GHC==7.10.3
22 GHC==8.0.2
24 GHC==8.0.2
23 GHC==8.2.2
25 GHC==8.2.2
24− GHC==8.4.3
26+ GHC==8.4.4
27+ GHC==8.6.1
28+
25homepage: http://haskell-servant.readthedocs.org/
29homepage: http://haskell-servant.readthedocs.org/
26Bug-reports: http://github.com/haskell-servant/servant/issues
30Bug-reports: http://github.com/haskell-servant/servant/issues
27extra-source-files:
31extra-source-files:
@@ -43,7 +47,7 @@ library
43 --
47 --
44 -- note: mtl lower bound is so low because of GHC-7.8
48 -- note: mtl lower bound is so low because of GHC-7.8
45 build-depends:
49 build-depends:
46− base >= 4.7 && < 4.12
50+ base >= 4.7 && < 4.13
47 , bytestring >= 0.10.4.0 && < 0.11
51 , bytestring >= 0.10.4.0 && < 0.11
48 , text >= 1.2.3.0 && < 1.3
52 , text >= 1.2.3.0 && < 1.3
49
53
@@ -64,9 +68,9 @@ library
64 , case-insensitive >= 1.2.0.10 && < 1.3
68 , case-insensitive >= 1.2.0.10 && < 1.3
65 , control-monad-omega >= 0.3.1 && < 0.4
69 , control-monad-omega >= 0.3.1 && < 0.4
66 , hashable >= 1.2.6.1 && < 1.3
70 , hashable >= 1.2.6.1 && < 1.3
67− , http-media >= 0.7.1.1 && < 0.8
71+ , http-media >= 0.7.0 && < 0.8
68 , http-types >= 0.12 && < 0.13
72 , http-types >= 0.12 && < 0.13
69− , lens >= 4.15.4 && < 4.17
73+ , lens >= 4.15.4 && < 4.18
70 , string-conversions >= 0.4.0.1 && < 0.5
74 , string-conversions >= 0.4.0.1 && < 0.5
71 , unordered-containers >= 0.2.8.0 && < 0.3
75 , unordered-containers >= 0.2.8.0 && < 0.3
72
76
servant-foreign/servant-foreign.cabal+8−4
@@ -1,6 +1,9 @@
1name: servant-foreign
1name: servant-foreign
2version: 0.11.1
2version: 0.11.1
3+x-revision: 4
4+
3synopsis: Helpers for generating clients for servant APIs in any programming language
5synopsis: Helpers for generating clients for servant APIs in any programming language
6+category: Servant, Web
4description:
7description:
5 Helper types and functions for generating client functions for servant APIs in any programming language
8 Helper types and functions for generating client functions for servant APIs in any programming language
6 .
9 .
@@ -9,12 +12,12 @@ description:
9 See the servant-js package for an example
12 See the servant-js package for an example
10 .
13 .
11 <https://github.com/haskell-servant/servant/blob/master/servant-foreign/CHANGELOG.md CHANGELOG>
14 <https://github.com/haskell-servant/servant/blob/master/servant-foreign/CHANGELOG.md CHANGELOG>
15+
12license: BSD3
16license: BSD3
13license-file: LICENSE
17license-file: LICENSE
14author: Servant Contributors
18author: Servant Contributors
15maintainer: haskell-servant-maintainers@googlegroups.com
19maintainer: haskell-servant-maintainers@googlegroups.com
16copyright: 2015-2016 Servant Contributors
20copyright: 2015-2016 Servant Contributors
17−category: Servant, Web
18build-type: Simple
21build-type: Simple
19cabal-version: >=1.10
22cabal-version: >=1.10
20extra-source-files:
23extra-source-files:
@@ -27,7 +30,8 @@ tested-with:
27 GHC==7.10.3
30 GHC==7.10.3
28 GHC==8.0.2
31 GHC==8.0.2
29 GHC==8.2.2
32 GHC==8.2.2
30− GHC==8.4.3
33+ GHC==8.4.4
34+ GHC==8.6.1
31
35
32source-repository head
36source-repository head
33 type: git
37 type: git
@@ -43,7 +47,7 @@ library
43 --
47 --
44 -- note: mtl lower bound is so low because of GHC-7.8
48 -- note: mtl lower bound is so low because of GHC-7.8
45 build-depends:
49 build-depends:
46− base >= 4.7 && <4.12
50+ base >= 4.7 && <4.13
47 , text >= 1.2.3.0 && < 1.3
51 , text >= 1.2.3.0 && < 1.3
48
52
49 if !impl(ghc >= 8.0)
53 if !impl(ghc >= 8.0)
@@ -58,7 +62,7 @@ library
58 -- Here can be exceptions if we really need features from the newer versions.
62 -- Here can be exceptions if we really need features from the newer versions.
59 build-depends:
63 build-depends:
60 base-compat >= 0.9.3 && <0.11
64 base-compat >= 0.9.3 && <0.11
61− , lens >= 4.15.4 && <4.17
65+ , lens >= 4.15.4 && <4.18
62 , http-types >= 0.12 && < 0.13
66 , http-types >= 0.12 && < 0.13
63
67
64 hs-source-dirs: src
68 hs-source-dirs: src
servant-server/CHANGELOG.md+56
@@ -1,6 +1,62 @@
1[The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant-server/CHANGELOG.md)
1[The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant-server/CHANGELOG.md)
2[Changelog for `servant` package contains significant entries for all core packages.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
2[Changelog for `servant` package contains significant entries for all core packages.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
3
3
4+0.14.1
5+------
6+
7+- Merge in `servant-generic` (by [Patrick Chilton](https://github.com/chpatrick))
8+ into `servant` (`Servant.API.Generic`),
9+ `servant-client-code` (`Servant.Client.Generic`)
10+ and `servant-server` (`Servant.Server.Generic`).
11+
12+- *servant-server* Deprecate `Servant.Utils.StaticUtils`, use `Servant.Server.StaticUtils`.
13+
14+0.14
15+----
16+
17+- `Stream` takes a status code argument
18+
19+ ```diff
20+ -Stream method framing ctype a
21+ +Stream method status framing ctype a
22+ ```
23+
24+ ([#966](https://github.com/haskell-servant/servant/pull/966)
25+ [#972](https://github.com/haskell-servant/servant/pull/972))
26+
27+- `ToStreamGenerator` definition changed, so it's possible to write an instance
28+ for conduits.
29+
30+ ```diff
31+ -class ToStreamGenerator f a where
32+ - toStreamGenerator :: f a -> StreamGenerator a
33+ +class ToStreamGenerator a b | a -> b where
34+ + toStreamGenerator :: a -> StreamGenerator b
35+ ```
36+
37+ ([#959](https://github.com/haskell-servant/servant/pull/959))
38+
39+- Added `NoFraming` streaming strategy
40+ ([#959](https://github.com/haskell-servant/servant/pull/959))
41+
42+- *servant-server* File serving in polymorphic monad.
43+ i.e. Generalised types of `serveDirectoryFileServer` etc functions in
44+ `Servant.Utils.StaticFiles`
45+ ([#953](https://github.com/haskell-servant/servant/pull/953))
46+
47+- *servant-server* `ReqBody` content type check is recoverable.
48+ This allows writing APIs like:
49+
50+ ```haskell
51+ ReqBody '[JSON] Int :> Post '[PlainText] Int
52+ :<|> ReqBody '[PlainText] Int :> Post '[PlainText] Int
53+ ```
54+
55+ which is useful when handlers are subtly different,
56+ for example may do less work.
57+ ([#937](https://github.com/haskell-servant/servant/pull/937))
58+
59+
40.13.0.1
600.13.0.1
5--------
61--------
6
62
servant-server/servant-server.cabal+40−38
@@ -1,6 +1,9 @@
1name: servant-server
1name: servant-server
2−version: 0.14
2+version: 0.14.1
3+x-revision: 1
4+
3synopsis: A family of combinators for defining webservices APIs and serving them
5synopsis: A family of combinators for defining webservices APIs and serving them
6+category: Servant, Web
4description:
7description:
5 A family of combinators for defining webservices APIs and serving them
8 A family of combinators for defining webservices APIs and serving them
6 .
9 .
@@ -11,6 +14,7 @@ description:
11 a webserver that serves this API, using this package.
14 a webserver that serves this API, using this package.
12 .
15 .
13 <https://github.com/haskell-servant/servant/blob/master/servant-server/CHANGELOG.md CHANGELOG>
16 <https://github.com/haskell-servant/servant/blob/master/servant-server/CHANGELOG.md CHANGELOG>
17+
14homepage: http://haskell-servant.readthedocs.org/
18homepage: http://haskell-servant.readthedocs.org/
15Bug-reports: http://github.com/haskell-servant/servant/issues
19Bug-reports: http://github.com/haskell-servant/servant/issues
16license: BSD3
20license: BSD3
@@ -18,7 +22,6 @@ license-file: LICENSE
18author: Servant Contributors
22author: Servant Contributors
19maintainer: haskell-servant-maintainers@googlegroups.com
23maintainer: haskell-servant-maintainers@googlegroups.com
20copyright: 2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
24copyright: 2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
21−category: Servant, Web
22build-type: Custom
25build-type: Custom
23cabal-version: >=1.10
26cabal-version: >=1.10
24tested-with:
27tested-with:
@@ -26,7 +29,9 @@ tested-with:
26 GHC==7.10.3
29 GHC==7.10.3
27 GHC==8.0.2
30 GHC==8.0.2
28 GHC==8.2.2
31 GHC==8.2.2
29− GHC==8.4.3
32+ GHC==8.4.4
33+ GHC==8.6.1
34+
30extra-source-files:
35extra-source-files:
31 include/*.h
36 include/*.h
32 CHANGELOG.md
37 CHANGELOG.md
@@ -40,13 +45,14 @@ custom-setup
40 setup-depends:
45 setup-depends:
41 base >= 4 && <5,
46 base >= 4 && <5,
42 Cabal,
47 Cabal,
43− cabal-doctest >= 1.0.1 && <1.1
48+ cabal-doctest >= 1.0.6 && <1.1
44
49
45library
50library
46 exposed-modules:
51 exposed-modules:
47 Servant
52 Servant
48 Servant.Server
53 Servant.Server
49 Servant.Server.Experimental.Auth
54 Servant.Server.Experimental.Auth
55+ Servant.Server.Generic
50 Servant.Server.Internal
56 Servant.Server.Internal
51 Servant.Server.Internal.BasicAuth
57 Servant.Server.Internal.BasicAuth
52 Servant.Server.Internal.Context
58 Servant.Server.Internal.Context
@@ -54,6 +60,10 @@ library
54 Servant.Server.Internal.Router
60 Servant.Server.Internal.Router
55 Servant.Server.Internal.RoutingApplication
61 Servant.Server.Internal.RoutingApplication
56 Servant.Server.Internal.ServantErr
62 Servant.Server.Internal.ServantErr
63+ Servant.Server.StaticFiles
64+
65+ -- deprecated
66+ exposed-modules:
57 Servant.Utils.StaticFiles
67 Servant.Utils.StaticFiles
58
68
59 -- Bundled with GHC: Lower bound to not force re-installs
69 -- Bundled with GHC: Lower bound to not force re-installs
@@ -61,9 +71,9 @@ library
61 --
71 --
62 -- note: mtl lower bound is so low because of GHC-7.8
72 -- note: mtl lower bound is so low because of GHC-7.8
63 build-depends:
73 build-depends:
64− base >= 4.7 && < 4.12
74+ base >= 4.7 && < 4.13
65 , bytestring >= 0.10.4.0 && < 0.11
75 , bytestring >= 0.10.4.0 && < 0.11
66− , containers >= 0.5.5.1 && < 0.6
76+ , containers >= 0.5.5.1 && < 0.7
67 , mtl >= 2.1 && < 2.3
77 , mtl >= 2.1 && < 2.3
68 , text >= 1.2.3.0 && < 1.3
78 , text >= 1.2.3.0 && < 1.3
69 , transformers >= 0.3.0.0 && < 0.6
79 , transformers >= 0.3.0.0 && < 0.6
@@ -71,37 +81,31 @@ library
71
81
72 if !impl(ghc >= 8.0)
82 if !impl(ghc >= 8.0)
73 build-depends:
83 build-depends:
74− semigroups >= 0.18.3 && < 0.19
84+ semigroups >= 0.18.4 && < 0.19
75
85
76 -- Servant dependencies
86 -- Servant dependencies
77 build-depends:
87 build-depends:
78− servant == 0.14.*
88+ servant >= 0.14.1 && <0.15
79
89
80 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
90 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
81 -- Here can be exceptions if we really need features from the newer versions.
91 -- Here can be exceptions if we really need features from the newer versions.
82 build-depends:
92 build-depends:
83− aeson >= 1.2.3.0 && < 1.5
84− , base-compat >= 0.9.3 && < 0.11
93+ base-compat >= 0.10.1 && < 0.11
85− , attoparsec >= 0.13.2.0 && < 0.14
86 , base64-bytestring >= 1.0.0.1 && < 1.1
94 , base64-bytestring >= 1.0.0.1 && < 1.1
87− , exceptions >= 0.8.3 && < 0.11
95+ , exceptions >= 0.10.0 && < 0.11
88− , http-api-data >= 0.3.7.1 && < 0.4
96+ , http-api-data >= 0.3.8.1 && < 0.4
89− , http-media >= 0.7.1.1 && < 0.8
97+ , http-media >= 0.7.1.2 && < 0.8
90− , http-types >= 0.12 && < 0.13
98+ , http-types >= 0.12.1 && < 0.13
91 , network-uri >= 2.6.1.0 && < 2.7
99 , network-uri >= 2.6.1.0 && < 2.7
92− , monad-control >= 1.0.0.4 && < 1.1
100+ , monad-control >= 1.0.2.3 && < 1.1
93− , network >= 2.6.3.2 && < 2.8
101+ , network >= 2.6.3.5 && < 2.9
94− , safe >= 0.3.15 && < 0.4
95− , split >= 0.2.3.2 && < 0.3
96 , string-conversions >= 0.4.0.1 && < 0.5
102 , string-conversions >= 0.4.0.1 && < 0.5
97− , system-filepath >= 0.4 && < 0.5
98− , resourcet >= 1.1.9 && < 1.3
103+ , resourcet >= 1.1.11 && < 1.3
99 , tagged >= 0.8.5 && < 0.9
104 , tagged >= 0.8.5 && < 0.9
100 , transformers-base >= 0.4.4 && < 0.5
105 , transformers-base >= 0.4.4 && < 0.5
101− , transformers-compat >= 0.5.1 && < 0.7
106+ , transformers-compat >= 0.6.2 && < 0.7
102 , wai >= 3.2.1.1 && < 3.3
107 , wai >= 3.2.1.1 && < 3.3
103 , wai-app-static >= 3.1.6.1 && < 3.2
108 , wai-app-static >= 3.1.6.1 && < 3.2
104− , warp >= 3.2.13 && < 3.3
105 , word8 >= 0.1.3 && < 0.2
109 , word8 >= 0.1.3 && < 0.2
106
110
107 hs-source-dirs: src
111 hs-source-dirs: src
@@ -120,11 +124,13 @@ executable greet
120 base
124 base
121 , servant
125 , servant
122 , servant-server
126 , servant-server
123− , aeson
124− , warp
125 , wai
127 , wai
126 , text
128 , text
127
129
130+ build-depends:
131+ aeson >= 1.3.1.1 && < 1.5
132+ , warp >= 3.2.13 && < 3.3
133+
128test-suite spec
134test-suite spec
129 type: exitcode-stdio-1.0
135 type: exitcode-stdio-1.0
130 ghc-options: -Wall
136 ghc-options: -Wall
@@ -137,24 +143,21 @@ test-suite spec
137 Servant.Server.Internal.ContextSpec
143 Servant.Server.Internal.ContextSpec
138 Servant.Server.Internal.RoutingApplicationSpec
144 Servant.Server.Internal.RoutingApplicationSpec
139 Servant.Server.RouterSpec
145 Servant.Server.RouterSpec
146+ Servant.Server.StaticFilesSpec
140 Servant.Server.StreamingSpec
147 Servant.Server.StreamingSpec
141 Servant.Server.UsingContextSpec
148 Servant.Server.UsingContextSpec
142 Servant.Server.UsingContextSpec.TestCombinators
149 Servant.Server.UsingContextSpec.TestCombinators
143 Servant.HoistSpec
150 Servant.HoistSpec
144 Servant.ServerSpec
151 Servant.ServerSpec
145− Servant.Utils.StaticFilesSpec
146
152
147 -- Dependencies inherited from the library. No need to specify bounds.
153 -- Dependencies inherited from the library. No need to specify bounds.
148 build-depends:
154 build-depends:
149 base
155 base
150 , base-compat
156 , base-compat
151− , aeson
152 , base64-bytestring
157 , base64-bytestring
153 , bytestring
158 , bytestring
154− , exceptions
155 , http-types
159 , http-types
156 , mtl
160 , mtl
157− , network
158 , resourcet
161 , resourcet
159 , safe
162 , safe
160 , servant
163 , servant
@@ -164,27 +167,26 @@ test-suite spec
164 , transformers
167 , transformers
165 , transformers-compat
168 , transformers-compat
166 , wai
169 , wai
167− , warp
168
170
169 -- Additonal dependencies
171 -- Additonal dependencies
170 build-depends:
172 build-depends:
173+ aeson >= 1.3.1.1 && < 1.5
171− directory >= 1.2.1.0 && < 1.4
174+ , directory >= 1.2.1.0 && < 1.4
172− , hspec >= 2.4.4 && < 2.6
175+ , hspec >= 2.5.1 && < 2.6
173− , hspec-wai >= 0.9 && < 0.10
176+ , hspec-wai >= 0.9.0 && < 0.10
177+ , QuickCheck >= 2.11.3 && < 2.13
174 , should-not-typecheck >= 2.1.0 && < 2.2
178 , should-not-typecheck >= 2.1.0 && < 2.2
175− , parsec >= 3.1.11 && < 3.2
179+ , temporary >= 1.3 && < 1.4
176− , QuickCheck >= 2.10.1 && < 2.12
177 , wai-extra >= 3.0.21.0 && < 3.1
180 , wai-extra >= 3.0.21.0 && < 3.1
178− , temporary >= 1.2.0.3 && < 1.4
179
181
180 build-tool-depends:
182 build-tool-depends:
181− hspec-discover:hspec-discover >=2.4.4 && <2.6
183+ hspec-discover:hspec-discover >= 2.5.1 && <2.6
182
184
183test-suite doctests
185test-suite doctests
184 build-depends:
186 build-depends:
185 base
187 base
186 , servant-server
188 , servant-server
187− , doctest >= 0.13.0 && <0.16
189+ , doctest >= 0.15.0 && <0.17
188 type: exitcode-stdio-1.0
190 type: exitcode-stdio-1.0
189 main-is: test/doctests.hs
191 main-is: test/doctests.hs
190 buildable: True
192 buildable: True
servant-server/src/Servant.hs+2−2
@@ -6,7 +6,7 @@ module Servant (
6 -- | For implementing servers for servant APIs.
6 -- | For implementing servers for servant APIs.
7 module Servant.Server,
7 module Servant.Server,
8 -- | Utilities on top of the servant core
8 -- | Utilities on top of the servant core
9− module Servant.Utils.Links,
9+ module Servant.Links,
10 module Servant.Utils.StaticFiles,
10 module Servant.Utils.StaticFiles,
11 -- | Useful re-exports
11 -- | Useful re-exports
12 Proxy(..),
12 Proxy(..),
@@ -17,5 +17,5 @@ import Control.Monad.Error.Class (throwError)
17import Data.Proxy
17import Data.Proxy
18import Servant.API
18import Servant.API
19import Servant.Server
19import Servant.Server
20−import Servant.Utils.Links
20+import Servant.Links
21import Servant.Utils.StaticFiles
21import Servant.Utils.StaticFiles
servant-server/src/Servant/Server/Generic.hsnew file+52
@@ -0,0 +1,52 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE KindSignatures #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE TypeFamilies #-}
7+{-# LANGUAGE TypeOperators #-}
8+{-# LANGUAGE UndecidableInstances #-}
9+-- | @since 0.14.1
10+module Servant.Server.Generic (
11+ AsServerT,
12+ AsServer,
13+ genericServe,
14+ genericServer,
15+ genericServerT,
16+ ) where
17+
18+import Data.Proxy
19+ (Proxy (..))
20+
21+import Servant.API.Generic
22+import Servant.Server
23+
24+-- | A type that specifies that an API record contains a server implementation.
25+data AsServerT (m :: * -> *)
26+instance GenericMode (AsServerT m) where
27+ type AsServerT m :- api = ServerT api m
28+
29+type AsServer = AsServerT Handler
30+
31+-- | Transform record of routes into a WAI 'Application'.
32+genericServe
33+ :: forall routes.
34+ ( HasServer (ToServantApi routes) '[]
35+ , GenericServant routes AsServer
36+ , Server (ToServantApi routes) ~ ToServant routes AsServer
37+ )
38+ => routes AsServer -> Application
39+genericServe = serve (Proxy :: Proxy (ToServantApi routes)) . genericServer
40+
41+-- | Transform record of endpoints into a 'Server'.
42+genericServer
43+ :: GenericServant routes AsServer
44+ => routes AsServer
45+ -> ToServant routes AsServer
46+genericServer = toServant
47+
48+genericServerT
49+ :: GenericServant routes (AsServerT m)
50+ => routes (AsServerT m)
51+ -> ToServant routes (AsServerT m)
52+genericServerT = toServant
servant-server/src/Servant/Server/Internal/Context.hs+1−1
@@ -18,7 +18,7 @@ import GHC.TypeLits
18-- | 'Context's are used to pass values to combinators. (They are __not__ meant
18-- | 'Context's are used to pass values to combinators. (They are __not__ meant
19-- to be used to pass parameters to your handlers, i.e. they should not replace
19-- to be used to pass parameters to your handlers, i.e. they should not replace
20-- any custom 'Control.Monad.Trans.Reader.ReaderT'-monad-stack that you're using
20-- any custom 'Control.Monad.Trans.Reader.ReaderT'-monad-stack that you're using
21−-- with 'Servant.Utils.Enter'.) If you don't use combinators that
21+-- with 'hoistServer'.) If you don't use combinators that
22-- require any context entries, you can just use 'Servant.Server.serve' as always.
22-- require any context entries, you can just use 'Servant.Server.serve' as always.
23--
23--
24-- If you are using combinators that require a non-empty 'Context' you have to
24-- If you are using combinators that require a non-empty 'Context' you have to
servant-server/src/Servant/Server/StaticFiles.hsnew file+92
@@ -0,0 +1,92 @@
1+{-# LANGUAGE CPP #-}
2+-- | This module defines server-side handlers that lets you serve static files.
3+--
4+-- The most common needs for a web application are covered by
5+-- 'serveDirectoryWebApp`, but the other variants allow you to use
6+-- different `StaticSettings` and 'serveDirectoryWith' even allows you
7+-- to specify arbitrary 'StaticSettings' to be used for serving static files.
8+module Servant.Server.StaticFiles
9+ ( serveDirectoryWebApp
10+ , serveDirectoryWebAppLookup
11+ , serveDirectoryFileServer
12+ , serveDirectoryEmbedded
13+ , serveDirectoryWith
14+ , -- * Deprecated
15+ serveDirectory
16+ ) where
17+
18+import Data.ByteString
19+ (ByteString)
20+import Network.Wai.Application.Static
21+import Servant.API.Raw
22+ (Raw)
23+import Servant.Server
24+ (ServerT, Tagged (..))
25+import System.FilePath
26+ (addTrailingPathSeparator)
27+#if !MIN_VERSION_wai_app_static(3,1,0)
28+import Filesystem.Path.CurrentOS
29+ (decodeString)
30+#endif
31+import WaiAppStatic.Storage.Filesystem
32+ (ETagLookup)
33+
34+-- | Serve anything under the specified directory as a 'Raw' endpoint.
35+--
36+-- @
37+-- type MyApi = "static" :> Raw
38+--
39+-- server :: Server MyApi
40+-- server = serveDirectoryWebApp "\/var\/www"
41+-- @
42+--
43+-- would capture any request to @\/static\/\<something>@ and look for
44+-- @\<something>@ under @\/var\/www@.
45+--
46+-- It will do its best to guess the MIME type for that file, based on the extension,
47+-- and send an appropriate /Content-Type/ header if possible.
48+--
49+-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API
50+-- as a webapp backend, you will most likely not want the static files to be hidden
51+-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectoryWebApp'
52+-- handler in the last position, because /servant/ will try to match the handlers
53+-- in order.
54+--
55+-- Corresponds to the `defaultWebAppSettings` `StaticSettings` value.
56+serveDirectoryWebApp :: FilePath -> ServerT Raw m
57+serveDirectoryWebApp = serveDirectoryWith . defaultWebAppSettings . fixPath
58+
59+-- | Same as 'serveDirectoryWebApp', but uses `defaultFileServerSettings`.
60+serveDirectoryFileServer :: FilePath -> ServerT Raw m
61+serveDirectoryFileServer = serveDirectoryWith . defaultFileServerSettings . fixPath
62+
63+-- | Same as 'serveDirectoryWebApp', but uses 'webAppSettingsWithLookup'.
64+serveDirectoryWebAppLookup :: ETagLookup -> FilePath -> ServerT Raw m
65+serveDirectoryWebAppLookup etag =
66+ serveDirectoryWith . flip webAppSettingsWithLookup etag . fixPath
67+
68+-- | Uses 'embeddedSettings'.
69+serveDirectoryEmbedded :: [(FilePath, ByteString)] -> ServerT Raw m
70+serveDirectoryEmbedded files = serveDirectoryWith (embeddedSettings files)
71+
72+-- | Alias for 'staticApp'. Lets you serve a directory
73+-- with arbitrary 'StaticSettings'. Useful when you want
74+-- particular settings not covered by the four other
75+-- variants. This is the most flexible method.
76+serveDirectoryWith :: StaticSettings -> ServerT Raw m
77+serveDirectoryWith = Tagged . staticApp
78+
79+-- | Same as 'serveDirectoryFileServer'. It used to be the only
80+-- file serving function in servant pre-0.10 and will be kept
81+-- around for a few versions, but is deprecated.
82+serveDirectory :: FilePath -> ServerT Raw m
83+serveDirectory = serveDirectoryFileServer
84+{-# DEPRECATED serveDirectory "Use serveDirectoryFileServer instead" #-}
85+
86+fixPath :: FilePath -> FilePath
87+fixPath =
88+#if MIN_VERSION_wai_app_static(3,1,0)
89+ addTrailingPathSeparator
90+#else
91+ decodeString . addTrailingPathSeparator
92+#endif
servant-server/src/Servant/Utils/StaticFiles.hs+4−84
@@ -1,86 +1,6 @@
1−{-# LANGUAGE CPP #-}
2−-- | This module defines server-side handlers that lets you serve static files.
3−--
4−-- The most common needs for a web application are covered by
5−-- 'serveDirectoryWebApp`, but the other variants allow you to use
6−-- different `StaticSettings` and 'serveDirectoryWith' even allows you
7−-- to specify arbitrary 'StaticSettings' to be used for serving static files.
8module Servant.Utils.StaticFiles
1module Servant.Utils.StaticFiles
9− ( serveDirectoryWebApp
2+ {-# DEPRECATED "Use Servant.ServerStaticFiles." #-}
10− , serveDirectoryWebAppLookup
3+ ( module Servant.Server.StaticFiles )
11− , serveDirectoryFileServer
12− , serveDirectoryEmbedded
13− , serveDirectoryWith
14− , -- * Deprecated
15− serveDirectory
16− ) where
4+ where
17
5
18−import Data.ByteString (ByteString)
19−import Network.Wai.Application.Static
20−import Servant.API.Raw (Raw)
21−import Servant.Server (ServerT, Tagged (..))
6+import Servant.Server.StaticFiles
22−import System.FilePath (addTrailingPathSeparator)
23−#if !MIN_VERSION_wai_app_static(3,1,0)
24−import Filesystem.Path.CurrentOS (decodeString)
25−#endif
26−import WaiAppStatic.Storage.Filesystem (ETagLookup)
27−
28−-- | Serve anything under the specified directory as a 'Raw' endpoint.
29−--
30−-- @
31−-- type MyApi = "static" :> Raw
32−--
33−-- server :: Server MyApi
34−-- server = serveDirectoryWebApp "\/var\/www"
35−-- @
36−--
37−-- would capture any request to @\/static\/\<something>@ and look for
38−-- @\<something>@ under @\/var\/www@.
39−--
40−-- It will do its best to guess the MIME type for that file, based on the extension,
41−-- and send an appropriate /Content-Type/ header if possible.
42−--
43−-- If your goal is to serve HTML, CSS and Javascript files that use the rest of the API
44−-- as a webapp backend, you will most likely not want the static files to be hidden
45−-- behind a /\/static\// prefix. In that case, remember to put the 'serveDirectoryWebApp'
46−-- handler in the last position, because /servant/ will try to match the handlers
47−-- in order.
48−--
49−-- Corresponds to the `defaultWebAppSettings` `StaticSettings` value.
50−serveDirectoryWebApp :: FilePath -> ServerT Raw m
51−serveDirectoryWebApp = serveDirectoryWith . defaultWebAppSettings . fixPath
52−
53−-- | Same as 'serveDirectoryWebApp', but uses `defaultFileServerSettings`.
54−serveDirectoryFileServer :: FilePath -> ServerT Raw m
55−serveDirectoryFileServer = serveDirectoryWith . defaultFileServerSettings . fixPath
56−
57−-- | Same as 'serveDirectoryWebApp', but uses 'webAppSettingsWithLookup'.
58−serveDirectoryWebAppLookup :: ETagLookup -> FilePath -> ServerT Raw m
59−serveDirectoryWebAppLookup etag =
60− serveDirectoryWith . flip webAppSettingsWithLookup etag . fixPath
61−
62−-- | Uses 'embeddedSettings'.
63−serveDirectoryEmbedded :: [(FilePath, ByteString)] -> ServerT Raw m
64−serveDirectoryEmbedded files = serveDirectoryWith (embeddedSettings files)
65−
66−-- | Alias for 'staticApp'. Lets you serve a directory
67−-- with arbitrary 'StaticSettings'. Useful when you want
68−-- particular settings not covered by the four other
69−-- variants. This is the most flexible method.
70−serveDirectoryWith :: StaticSettings -> ServerT Raw m
71−serveDirectoryWith = Tagged . staticApp
72−
73−-- | Same as 'serveDirectoryFileServer'. It used to be the only
74−-- file serving function in servant pre-0.10 and will be kept
75−-- around for a few versions, but is deprecated.
76−serveDirectory :: FilePath -> ServerT Raw m
77−serveDirectory = serveDirectoryFileServer
78−{-# DEPRECATED serveDirectory "Use serveDirectoryFileServer instead" #-}
79−
80−fixPath :: FilePath -> FilePath
81−fixPath =
82−#if MIN_VERSION_wai_app_static(3,1,0)
83− addTrailingPathSeparator
84−#else
85− decodeString . addTrailingPathSeparator
86−#endif
servant-server/test/Servant/Utils/StaticFilesSpec.hs → servant-server/test/Servant/Server/StaticFilesSpec.hsrenamed+25−16
@@ -3,22 +3,31 @@
3{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeOperators #-}
5{-# OPTIONS_GHC -fno-warn-orphans #-}
5{-# OPTIONS_GHC -fno-warn-orphans #-}
6−module Servant.Utils.StaticFilesSpec where
6+module Servant.Server.StaticFilesSpec where
7−
7+
8−import Control.Exception (bracket)
8+import Control.Exception
9+ (bracket)
9−import Data.Proxy (Proxy (Proxy))
10+import Data.Proxy
11+ (Proxy (Proxy))
10−import Network.Wai (Application)
12+import Network.Wai
13+ (Application)
11−import System.Directory (createDirectory,
14+import System.Directory
12− getCurrentDirectory,
15+ (createDirectory, getCurrentDirectory, setCurrentDirectory)
13− setCurrentDirectory)
16+import System.IO.Temp
14−import System.IO.Temp (withSystemTempDirectory)
17+ (withSystemTempDirectory)
18+import Test.Hspec
15−import Test.Hspec (Spec, around_, describe, it)
19+ (Spec, around_, describe, it)
20+import Test.Hspec.Wai
16−import Test.Hspec.Wai (get, shouldRespondWith, with)
21+ (get, shouldRespondWith, with)
17−
22+
18−import Servant.API ((:<|>) ((:<|>)), Capture, Get, Raw, (:>), JSON)
23+import Servant.API
24+ ((:<|>) ((:<|>)), (:>), Capture, Get, JSON, Raw)
19−import Servant.Server (Server, serve)
25+import Servant.Server
26+ (Server, serve)
20−import Servant.ServerSpec (Person (Person))
27+import Servant.Server.StaticFiles
21−import Servant.Utils.StaticFiles (serveDirectoryFileServer)
28+ (serveDirectoryFileServer)
29+import Servant.ServerSpec
30+ (Person (Person))
22
31
23type Api =
32type Api =
24 "dummy_api" :> Capture "person_name" String :> Get '[JSON] Person
33 "dummy_api" :> Capture "person_name" String :> Get '[JSON] Person
servant/CHANGELOG.md+27−5
@@ -1,5 +1,18 @@
1[The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
1[The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
2
2
3+0.14.1
4+------
5+
6+- Merge in (and slightly refactor) `servant-generic`
7+ (by [Patrick Chilton](https://github.com/chpatrick))
8+ into `servant` (`Servant.API.Generic`),
9+ `servant-client-code` (`Servant.Client.Generic`)
10+ and `servant-server` (`Servant.Server.Generic`).
11+
12+- Deprecate `Servant.Utils.Links`, use `Servant.Links`.
13+
14+- *servant-server* Deprecate `Servant.Utils.StaticUtils`, use `Servant.Server.StaticUtils`.
15+
30.14
160.14
4----
17----
5
18
@@ -30,16 +43,25 @@
30- Added `NoFraming` streaming strategy
43- Added `NoFraming` streaming strategy
31 ([#959](https://github.com/haskell-servant/servant/pull/959))
44 ([#959](https://github.com/haskell-servant/servant/pull/959))
32
45
33−- *servant-client* Free `Client` implementation.
46+- *servant-client-core* Free `Client` implementation.
34 Useful for testing `HasClient` instances.
47 Useful for testing `HasClient` instances.
35 ([#920](https://github.com/haskell-servant/servant/pull/920))
48 ([#920](https://github.com/haskell-servant/servant/pull/920))
36
49
37−- *servant-client* Add `hoistClient` to `HasClient`.
50+- *servant-client-core* Add `hoistClient` to `HasClient`.
38 Just like `hoistServer` allows us to change the monad in which request handlers
51 Just like `hoistServer` allows us to change the monad in which request handlers
39 of a web application live in, we also have `hoistClient` for changing the monad
52 of a web application live in, we also have `hoistClient` for changing the monad
40− in which *client functions* live. Read [tutorial section for more information](#link).
53+ in which *client functions* live.
54+ Read [tutorial section for more information](https://haskell-servant.readthedocs.io/en/release-0.14/tutorial/Client.html#changing-the-monad-the-client-functions-live-in).
41 ([#936](https://github.com/haskell-servant/servant/pull/936))
55 ([#936](https://github.com/haskell-servant/servant/pull/936))
42
56
57+ iF you have own combinators, you'll need to define a new method of
58+ `HasClient` class, for example:
59+
60+ ```haskell
61+ type Client m (MyCombinator :> api) = MyValue :> Client m api
62+ hoistClientMonad pm _ nt cl = hoistClientMonad pm (Proxy :: Proxy api) nt . cl
63+ ```
64+
43- *servant* Add `safeLink' :: (Link -> a) -> ... -> MkLink endpoint a`,
65- *servant* Add `safeLink' :: (Link -> a) -> ... -> MkLink endpoint a`,
44 which allows to create helpers returning something else than `Link`.
66 which allows to create helpers returning something else than `Link`.
45 ([#968](https://github.com/haskell-servant/servant/pull/968))
67 ([#968](https://github.com/haskell-servant/servant/pull/968))
@@ -76,10 +98,10 @@
76- Added tests or enabled tests
98- Added tests or enabled tests
77 ([#975](https://github.com/haskell-servant/servant/pull/975))
99 ([#975](https://github.com/haskell-servant/servant/pull/975))
78
100
79−- Add [pagination cookbook recipe](#link)
101+- Add [pagination cookbook recipe](https://haskell-servant.readthedocs.io/en/release-0.14/cookbook/pagination/Pagination.html)
80 ([#946](https://github.com/haskell-servant/servant/pull/946))
102 ([#946](https://github.com/haskell-servant/servant/pull/946))
81
103
82−- Add [`servant-flatten` cookbook recipe](#link)
104+- Add [`servant-flatten` "spice" to the structuring api recipe](https://haskell-servant.readthedocs.io/en/release-0.14/cookbook/structuring-apis/StructuringApis.html)
83 ([#929](https://github.com/haskell-servant/servant/pull/929))
105 ([#929](https://github.com/haskell-servant/servant/pull/929))
84
106
85- Dependency updates
107- Dependency updates
servant/servant.cabal+34−25
@@ -1,12 +1,16 @@
1name: servant
1name: servant
2−version: 0.14
2+version: 0.14.1
3+x-revision: 1
4+
3synopsis: A family of combinators for defining webservices APIs
5synopsis: A family of combinators for defining webservices APIs
6+category: Servant, Web
4description:
7description:
5 A family of combinators for defining webservices APIs and serving them
8 A family of combinators for defining webservices APIs and serving them
6 .
9 .
7 You can learn about the basics in the <http://haskell-servant.readthedocs.org/en/stable/tutorial/index.html tutorial>.
10 You can learn about the basics in the <http://haskell-servant.readthedocs.org/en/stable/tutorial/index.html tutorial>.
8 .
11 .
9 <https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md CHANGELOG>
12 <https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md CHANGELOG>
13+
10homepage: http://haskell-servant.readthedocs.org/
14homepage: http://haskell-servant.readthedocs.org/
11Bug-reports: http://github.com/haskell-servant/servant/issues
15Bug-reports: http://github.com/haskell-servant/servant/issues
12license: BSD3
16license: BSD3
@@ -14,7 +18,6 @@ license-file: LICENSE
14author: Servant Contributors
18author: Servant Contributors
15maintainer: haskell-servant-maintainers@googlegroups.com
19maintainer: haskell-servant-maintainers@googlegroups.com
16copyright: 2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
20copyright: 2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
17−category: Servant, Web
18build-type: Custom
21build-type: Custom
19cabal-version: >=1.10
22cabal-version: >=1.10
20tested-with:
23tested-with:
@@ -22,7 +25,9 @@ tested-with:
22 GHC==7.10.3
25 GHC==7.10.3
23 GHC==8.0.2
26 GHC==8.0.2
24 GHC==8.2.2
27 GHC==8.2.2
25− GHC==8.4.3
28+ GHC==8.4.4
29+ GHC==8.6.1
30+
26extra-source-files:
31extra-source-files:
27 include/*.h
32 include/*.h
28 CHANGELOG.md
33 CHANGELOG.md
@@ -34,7 +39,7 @@ custom-setup
34 setup-depends:
39 setup-depends:
35 base >= 4 && <5,
40 base >= 4 && <5,
36 Cabal,
41 Cabal,
37− cabal-doctest >= 1.0.2 && <1.1
42+ cabal-doctest >= 1.0.6 && <1.1
38
43
39library
44library
40 exposed-modules:
45 exposed-modules:
@@ -46,6 +51,7 @@ library
46 Servant.API.Description
51 Servant.API.Description
47 Servant.API.Empty
52 Servant.API.Empty
48 Servant.API.Experimental.Auth
53 Servant.API.Experimental.Auth
54+ Servant.API.Generic
49 Servant.API.Header
55 Servant.API.Header
50 Servant.API.HttpVersion
56 Servant.API.HttpVersion
51 Servant.API.Internal.Test.ComprehensiveAPI
57 Servant.API.Internal.Test.ComprehensiveAPI
@@ -62,6 +68,10 @@ library
62 Servant.API.Vault
68 Servant.API.Vault
63 Servant.API.Verbs
69 Servant.API.Verbs
64 Servant.API.WithNamedContext
70 Servant.API.WithNamedContext
71+ Servant.Links
72+
73+ -- Deprecated modules, to be removed in late 2019
74+ exposed-modules:
65 Servant.Utils.Links
75 Servant.Utils.Links
66 Servant.Utils.Enter
76 Servant.Utils.Enter
67
77
@@ -70,32 +80,32 @@ library
70 --
80 --
71 -- note: mtl lower bound is so low because of GHC-7.8
81 -- note: mtl lower bound is so low because of GHC-7.8
72 build-depends:
82 build-depends:
73− base >= 4.7 && < 4.12
83+ base >= 4.7 && < 4.13
74 , bytestring >= 0.10.4.0 && < 0.11
84 , bytestring >= 0.10.4.0 && < 0.11
75 , mtl >= 2.1 && < 2.3
85 , mtl >= 2.1 && < 2.3
76 , text >= 1.2.3.0 && < 1.3
86 , text >= 1.2.3.0 && < 1.3
77
87
78 if !impl(ghc >= 8.0)
88 if !impl(ghc >= 8.0)
79 build-depends:
89 build-depends:
80− semigroups >= 0.18.3 && < 0.19
90+ semigroups >= 0.18.4 && < 0.19
81
91
82 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
92 -- Other dependencies: Lower bound around what is in the latest Stackage LTS.
83 -- Here can be exceptions if we really need features from the newer versions.
93 -- Here can be exceptions if we really need features from the newer versions.
84 build-depends:
94 build-depends:
85− base-compat >= 0.9.3 && < 0.11
95+ base-compat >= 0.10.1 && < 0.11
86− , aeson >= 1.2.3.0 && < 1.5
96+ , aeson >= 1.3.1.1 && < 1.5
87− , attoparsec >= 0.13.2.0 && < 0.14
97+ , attoparsec >= 0.13.2.2 && < 0.14
88 , case-insensitive >= 1.2.0.10 && < 1.3
98 , case-insensitive >= 1.2.0.10 && < 1.3
89− , http-api-data >= 0.3.7.1 && < 0.4
99+ , http-api-data >= 0.3.8.1 && < 0.4
90− , http-media >= 0.7.1.1 && < 0.8
100+ , http-media >= 0.7.1.2 && < 0.8
91− , http-types >= 0.12 && < 0.13
101+ , http-types >= 0.12.1 && < 0.13
92 , natural-transformation >= 0.4 && < 0.5
102 , natural-transformation >= 0.4 && < 0.5
93− , mmorph >= 1.1.0 && < 1.2
103+ , mmorph >= 1.1.2 && < 1.2
94 , tagged >= 0.8.5 && < 0.9
104 , tagged >= 0.8.5 && < 0.9
95− , singleton-bool >= 0.1.2.0 && < 0.2
105+ , singleton-bool >= 0.1.4 && < 0.2
96 , string-conversions >= 0.4.0.1 && < 0.5
106 , string-conversions >= 0.4.0.1 && < 0.5
97 , network-uri >= 2.6.1.0 && < 2.7
107 , network-uri >= 2.6.1.0 && < 2.7
98− , vault >= 0.3.0.7 && < 0.4
108+ , vault >= 0.3.1.1 && < 0.4
99
109
100 hs-source-dirs: src
110 hs-source-dirs: src
101 default-language: Haskell2010
111 default-language: Haskell2010
@@ -133,15 +143,14 @@ test-suite spec
133 other-modules:
143 other-modules:
134 Servant.API.ContentTypesSpec
144 Servant.API.ContentTypesSpec
135 Servant.API.ResponseHeadersSpec
145 Servant.API.ResponseHeadersSpec
136− Servant.Utils.LinksSpec
137 Servant.Utils.EnterSpec
146 Servant.Utils.EnterSpec
147+ Servant.LinksSpec
138
148
139 -- Dependencies inherited from the library. No need to specify bounds.
149 -- Dependencies inherited from the library. No need to specify bounds.
140 build-depends:
150 build-depends:
141 base
151 base
142 , base-compat
152 , base-compat
143 , aeson
153 , aeson
144− , attoparsec
145 , bytestring
154 , bytestring
146 , servant
155 , servant
147 , string-conversions
156 , string-conversions
@@ -153,23 +162,23 @@ test-suite spec
153
162
154 -- Additonal dependencies
163 -- Additonal dependencies
155 build-depends:
164 build-depends:
156− aeson-compat >= 0.3.3 && < 0.4
165+ aeson-compat >= 0.3.7.1 && < 0.4
157− , hspec >= 2.4.4 && < 2.6
166+ , hspec >= 2.5.1 && < 2.6
158− , QuickCheck >= 2.10.1 && < 2.12
167+ , QuickCheck >= 2.11.3 && < 2.13
159− , quickcheck-instances >= 0.3.16 && < 0.4
168+ , quickcheck-instances >= 0.3.18 && < 0.4
160
169
161 build-tool-depends:
170 build-tool-depends:
162− hspec-discover:hspec-discover >= 2.4.4 && < 2.6
171+ hspec-discover:hspec-discover >= 2.5.1 && < 2.6
163
172
164test-suite doctests
173test-suite doctests
165 build-depends:
174 build-depends:
166 base
175 base
167 , servant
176 , servant
168− , doctest >= 0.13.0 && <0.16
177+ , doctest >= 0.15.0 && <0.17
169
178
170 -- We test Links failure with doctest, so we need extra dependencies
179 -- We test Links failure with doctest, so we need extra dependencies
171 build-depends:
180 build-depends:
172− hspec >= 2.4.4 && < 2.6
181+ hspec >= 2.5.1 && < 2.6
173
182
174 type: exitcode-stdio-1.0
183 type: exitcode-stdio-1.0
175 main-is: test/doctests.hs
184 main-is: test/doctests.hs
@@ -180,4 +189,4 @@ test-suite doctests
180 x-doctest-options: -fdiagnostics-color=never
189 x-doctest-options: -fdiagnostics-color=never
181 include-dirs: include
190 include-dirs: include
182 x-doctest-source-dirs: test
191 x-doctest-source-dirs: test
183− x-doctest-modules: Servant.Utils.LinksSpec
192+ x-doctest-modules: Servant.LinksSpec
servant/src/Servant/API.hs+3−3
@@ -63,8 +63,8 @@ module Servant.API (
63 module Servant.API.Experimental.Auth,
63 module Servant.API.Experimental.Auth,
64 -- | General Authentication
64 -- | General Authentication
65
65
66− -- * Utilities
66+ -- * Links
67− module Servant.Utils.Links,
67+ module Servant.Links,
68 -- | Type-safe internal URIs
68 -- | Type-safe internal URIs
69
69
70 -- * Re-exports
70 -- * Re-exports
@@ -134,7 +134,7 @@ import Servant.API.Verbs
134 ReflectMethod (reflectMethod), StdMethod (..), Verb)
134 ReflectMethod (reflectMethod), StdMethod (..), Verb)
135import Servant.API.WithNamedContext
135import Servant.API.WithNamedContext
136 (WithNamedContext)
136 (WithNamedContext)
137−import Servant.Utils.Links
137+import Servant.Links
138 (HasLink (..), IsElem, IsElem', Link, URI (..), safeLink)
138 (HasLink (..), IsElem, IsElem', Link, URI (..), safeLink)
139import Web.HttpApiData
139import Web.HttpApiData
140 (FromHttpApiData (..), ToHttpApiData (..))
140 (FromHttpApiData (..), ToHttpApiData (..))
servant/src/Servant/API/Generic.hsnew file+146
@@ -0,0 +1,146 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE TypeOperators #-}
5+-- | Define servant servers from record types. Generics for the win.
6+--
7+-- The usage is simple, if you only need a collection of routes. First you
8+-- define a record with field types prefixed by a parameter `route`:
9+--
10+-- @
11+-- data Routes route = Routes
12+-- { _get :: route :- Capture "id" Int :> Get '[JSON] String
13+-- , _put :: route :- ReqBody '[JSON] Int :> Put '[JSON] Bool
14+-- }
15+-- deriving ('Generic')
16+-- @
17+--
18+-- You can get a 'Proxy' of the server using
19+--
20+-- @
21+-- api :: Proxy (ToServantApi Routes)
22+-- api = genericApi (Proxy :: Proxy Routes)
23+-- @
24+--
25+-- Using 'genericApi' is better as it checks that instances exists,
26+-- i.e. you get better error messages than simply using 'Proxy' value.
27+--
28+-- __Note:__ in 0.14 series this module isn't re-exported from 'Servant.API'.
29+--
30+-- "Servant.API.Generic" is based on @servant-generic@ package by
31+-- [Patrick Chilton](https://github.com/chpatrick)
32+--
33+-- @since 0.14.1
34+module Servant.API.Generic (
35+ GenericMode (..),
36+ GenericServant,
37+ ToServant,
38+ toServant,
39+ fromServant,
40+ -- * AsApi
41+ AsApi,
42+ ToServantApi,
43+ genericApi,
44+ -- * Utility
45+ GServantProduct,
46+ -- * re-exports
47+ Generic (Rep),
48+ ) where
49+
50+-- Based on servant-generic licensed under MIT License
51+--
52+-- Copyright (c) 2017 Patrick Chilton
53+--
54+-- Permission is hereby granted, free of charge, to any person obtaining a copy
55+-- of this software and associated documentation files (the "Software"), to deal
56+-- in the Software without restriction, including without limitation the rights
57+-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58+-- copies of the Software, and to permit persons to whom the Software is
59+-- furnished to do so, subject to the following conditions:
60+--
61+-- The above copyright notice and this permission notice shall be included in all
62+-- copies or substantial portions of the Software.
63+--
64+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66+-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67+-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68+-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69+-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
70+-- SOFTWARE.
71+
72+import Data.Proxy
73+ (Proxy (..))
74+import GHC.Generics
75+ ((:*:) (..), Generic (..), K1 (..), M1 (..))
76+
77+import Servant.API.Alternative
78+
79+-- | A constraint alias, for work with 'mode' and 'routes'.
80+type GenericServant routes mode = (GenericMode mode, Generic (routes mode), GServantProduct (Rep (routes mode)))
81+
82+-- | A class with a type family that applies an appropriate type family to the @api@
83+-- parameter. For example, 'AsApi' will leave @api@ untouched, while
84+-- @'AsServerT' m@ will produce @'ServerT' api m@.
85+class GenericMode mode where
86+ type mode :- api :: *
87+
88+infixl 0 :-
89+
90+-- | Turns a generic product type into a tree of `:<|>` combinators.
91+type ToServant routes mode = GToServant (Rep (routes mode))
92+
93+type ToServantApi routes = ToServant routes AsApi
94+
95+-- | See `ToServant`, but at value-level.
96+toServant
97+ :: GenericServant routes mode
98+ => routes mode -> ToServant routes mode
99+toServant = gtoServant . from
100+
101+-- | Inverse of `toServant`.
102+--
103+-- This can be used to turn 'generated' values such as client functions into records.
104+--
105+-- You may need to provide a type signature for the /output/ type (your record type).
106+fromServant
107+ :: GenericServant routes mode
108+ => ToServant routes mode -> routes mode
109+fromServant = to . gfromServant
110+
111+-- | A type that specifies that an API record contains an API definition. Only useful at type-level.
112+data AsApi
113+instance GenericMode AsApi where
114+ type AsApi :- api = api
115+
116+-- | Get a 'Proxy' of an API type.
117+genericApi
118+ :: GenericServant routes AsApi
119+ => Proxy routes
120+ -> Proxy (ToServantApi routes)
121+genericApi _ = Proxy
122+
123+-------------------------------------------------------------------------------
124+-- Class
125+-------------------------------------------------------------------------------
126+
127+
128+class GServantProduct f where
129+ type GToServant f
130+ gtoServant :: f p -> GToServant f
131+ gfromServant :: GToServant f -> f p
132+
133+instance GServantProduct f => GServantProduct (M1 i c f) where
134+ type GToServant (M1 i c f) = GToServant f
135+ gtoServant = gtoServant . unM1
136+ gfromServant = M1 . gfromServant
137+
138+instance (GServantProduct l, GServantProduct r) => GServantProduct (l :*: r) where
139+ type GToServant (l :*: r) = GToServant l :<|> GToServant r
140+ gtoServant (l :*: r) = gtoServant l :<|> gtoServant r
141+ gfromServant (l :<|> r) = gfromServant l :*: gfromServant r
142+
143+instance GServantProduct (K1 i c) where
144+ type GToServant (K1 i c) = c
145+ gtoServant = unK1
146+ gfromServant = K1
servant/src/Servant/API/Verbs.hs+1−1
@@ -58,7 +58,7 @@ type Patch = Verb 'PATCH 200
58--
58--
59-- If the resource cannot be created immediately, use 'PostAccepted'.
59-- If the resource cannot be created immediately, use 'PostAccepted'.
60--
60--
61−-- Consider using 'Servant.Utils.Links.safeLink' for the @Location@ header
61+-- Consider using 'Servant.Links.safeLink' for the @Location@ header
62-- field.
62-- field.
63
63
64-- | 'POST' with 201 status code.
64-- | 'POST' with 201 status code.
servant/src/Servant/Links.hsnew file+573
@@ -0,0 +1,573 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE FunctionalDependencies #-}
6+{-# LANGUAGE PolyKinds #-}
7+{-# LANGUAGE ScopedTypeVariables #-}
8+{-# LANGUAGE TypeFamilies #-}
9+{-# LANGUAGE TypeOperators #-}
10+{-# LANGUAGE UndecidableInstances #-}
11+{-# OPTIONS_HADDOCK not-home #-}
12+
13+-- | Type safe generation of internal links.
14+--
15+-- Given an API with a few endpoints:
16+--
17+-- >>> :set -XDataKinds -XTypeFamilies -XTypeOperators
18+-- >>> import Servant.API
19+-- >>> import Servant.Links
20+-- >>> import Data.Proxy
21+-- >>>
22+-- >>> type Hello = "hello" :> Get '[JSON] Int
23+-- >>> type Bye = "bye" :> QueryParam "name" String :> Delete '[JSON] NoContent
24+-- >>> type API = Hello :<|> Bye
25+-- >>> let api = Proxy :: Proxy API
26+--
27+-- It is possible to generate links that are guaranteed to be within 'API' with
28+-- 'safeLink'. The first argument to 'safeLink' is a type representing the API
29+-- you would like to restrict links to. The second argument is the destination
30+-- endpoint you would like the link to point to, this will need to end with a
31+-- verb like GET or POST. Further arguments may be required depending on the
32+-- type of the endpoint. If everything lines up you will get a 'Link' out the
33+-- other end.
34+--
35+-- You may omit 'QueryParam's and the like should you not want to provide them,
36+-- but types which form part of the URL path like 'Capture' must be included.
37+-- The reason you may want to omit 'QueryParam's is that safeLink is a bit
38+-- magical: if parameters are included that could take input it will return a
39+-- function that accepts that input and generates a link. This is best shown
40+-- with an example. Here, a link is generated with no parameters:
41+--
42+-- >>> let hello = Proxy :: Proxy ("hello" :> Get '[JSON] Int)
43+-- >>> toUrlPiece (safeLink api hello :: Link)
44+-- "hello"
45+--
46+-- If the API has an endpoint with parameters then we can generate links with
47+-- or without those:
48+--
49+-- >>> let with = Proxy :: Proxy ("bye" :> QueryParam "name" String :> Delete '[JSON] NoContent)
50+-- >>> toUrlPiece $ safeLink api with (Just "Hubert")
51+-- "bye?name=Hubert"
52+--
53+-- >>> let without = Proxy :: Proxy ("bye" :> Delete '[JSON] NoContent)
54+-- >>> toUrlPiece $ safeLink api without
55+-- "bye"
56+--
57+-- If you would like create a helper for generating links only within that API,
58+-- you can partially apply safeLink if you specify a correct type signature
59+-- like so:
60+--
61+-- >>> :set -XConstraintKinds
62+-- >>> :{
63+-- >>> let apiLink :: (IsElem endpoint API, HasLink endpoint)
64+-- >>> => Proxy endpoint -> MkLink endpoint Link
65+-- >>> apiLink = safeLink api
66+-- >>> :}
67+--
68+-- `safeLink'` allows to make specialise the output:
69+--
70+-- >>> safeLink' toUrlPiece api without
71+-- "bye"
72+--
73+-- >>> :{
74+-- >>> let apiTextLink :: (IsElem endpoint API, HasLink endpoint)
75+-- >>> => Proxy endpoint -> MkLink endpoint Text
76+-- >>> apiTextLink = safeLink' toUrlPiece api
77+-- >>> :}
78+--
79+-- >>> apiTextLink without
80+-- "bye"
81+--
82+-- Attempting to construct a link to an endpoint that does not exist in api
83+-- will result in a type error like this:
84+--
85+-- >>> let bad_link = Proxy :: Proxy ("hello" :> Delete '[JSON] NoContent)
86+-- >>> safeLink api bad_link
87+-- ...
88+-- ...Could not deduce...
89+-- ...
90+--
91+-- This error is essentially saying that the type family couldn't find
92+-- bad_link under api after trying the open (but empty) type family
93+-- `IsElem'` as a last resort.
94+--
95+-- @since 0.14.1
96+module Servant.Links (
97+ module Servant.API.TypeLevel,
98+
99+ -- * Building and using safe links
100+ --
101+ -- | Note that 'URI' is from the "Network.URI" module in the @network-uri@ package.
102+ safeLink
103+ , safeLink'
104+ , allLinks
105+ , allLinks'
106+ , URI(..)
107+ -- * Generics
108+ , AsLink
109+ , fieldLink
110+ , fieldLink'
111+ , allFieldLinks
112+ , allFieldLinks'
113+ -- * Adding custom types
114+ , HasLink(..)
115+ , Link
116+ , linkURI
117+ , linkURI'
118+ , LinkArrayElementStyle (..)
119+ -- ** Link accessors
120+ , Param (..)
121+ , linkSegments
122+ , linkQueryParams
123+) where
124+
125+import Data.List
126+import Data.Proxy
127+ (Proxy (..))
128+import Data.Semigroup
129+ ((<>))
130+import Data.Singletons.Bool
131+ (SBool (..), SBoolI (..))
132+import qualified Data.Text as Text
133+import qualified Data.Text.Encoding as TE
134+import Data.Type.Bool
135+ (If)
136+import GHC.TypeLits
137+ (KnownSymbol, symbolVal)
138+import Network.URI
139+ (URI (..), escapeURIString, isUnreserved)
140+import Prelude ()
141+import Prelude.Compat
142+
143+import Servant.API.Alternative
144+ ((:<|>) ((:<|>)))
145+import Servant.API.BasicAuth
146+ (BasicAuth)
147+import Servant.API.Capture
148+ (Capture', CaptureAll)
149+import Servant.API.Description
150+ (Description, Summary)
151+import Servant.API.Empty
152+ (EmptyAPI (..))
153+import Servant.API.Experimental.Auth
154+ (AuthProtect)
155+import Servant.API.Generic
156+import Servant.API.Header
157+ (Header')
158+import Servant.API.HttpVersion
159+ (HttpVersion)
160+import Servant.API.IsSecure
161+ (IsSecure)
162+import Servant.API.Modifiers
163+ (FoldRequired)
164+import Servant.API.QueryParam
165+ (QueryFlag, QueryParam', QueryParams)
166+import Servant.API.Raw
167+ (Raw)
168+import Servant.API.RemoteHost
169+ (RemoteHost)
170+import Servant.API.ReqBody
171+ (ReqBody')
172+import Servant.API.Stream
173+ (Stream)
174+import Servant.API.Sub
175+ (type (:>))
176+import Servant.API.TypeLevel
177+import Servant.API.Vault
178+ (Vault)
179+import Servant.API.Verbs
180+ (Verb)
181+import Servant.API.WithNamedContext
182+ (WithNamedContext)
183+import Web.HttpApiData
184+
185+-- | A safe link datatype.
186+-- The only way of constructing a 'Link' is using 'safeLink', which means any
187+-- 'Link' is guaranteed to be part of the mentioned API.
188+data Link = Link
189+ { _segments :: [Escaped]
190+ , _queryParams :: [Param]
191+ } deriving Show
192+
193+newtype Escaped = Escaped String
194+
195+escaped :: String -> Escaped
196+escaped = Escaped . escapeURIString isUnreserved
197+
198+getEscaped :: Escaped -> String
199+getEscaped (Escaped s) = s
200+
201+instance Show Escaped where
202+ showsPrec d (Escaped s) = showsPrec d s
203+ show (Escaped s) = show s
204+
205+linkSegments :: Link -> [String]
206+linkSegments = map getEscaped . _segments
207+
208+linkQueryParams :: Link -> [Param]
209+linkQueryParams = _queryParams
210+
211+instance ToHttpApiData Link where
212+ toHeader = TE.encodeUtf8 . toUrlPiece
213+ toUrlPiece l =
214+ let uri = linkURI l
215+ in Text.pack $ uriPath uri ++ uriQuery uri
216+
217+-- | Query parameter.
218+data Param
219+ = SingleParam String Text.Text
220+ | ArrayElemParam String Text.Text
221+ | FlagParam String
222+ deriving Show
223+
224+addSegment :: Escaped -> Link -> Link
225+addSegment seg l = l { _segments = _segments l <> [seg] }
226+
227+addQueryParam :: Param -> Link -> Link
228+addQueryParam qp l =
229+ l { _queryParams = _queryParams l <> [qp] }
230+
231+-- | Transform 'Link' into 'URI'.
232+--
233+-- >>> type API = "something" :> Get '[JSON] Int
234+-- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API)
235+-- something
236+--
237+-- >>> type API = "sum" :> QueryParams "x" Int :> Get '[JSON] Int
238+-- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API) [1, 2, 3]
239+-- sum?x[]=1&x[]=2&x[]=3
240+--
241+-- >>> type API = "foo/bar" :> Get '[JSON] Int
242+-- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API)
243+-- foo%2Fbar
244+--
245+-- >>> type SomeRoute = "abc" :> Capture "email" String :> Put '[JSON] ()
246+-- >>> let someRoute = Proxy :: Proxy SomeRoute
247+-- >>> safeLink someRoute someRoute "test@example.com"
248+-- Link {_segments = ["abc","test%40example.com"], _queryParams = []}
249+--
250+-- >>> linkURI $ safeLink someRoute someRoute "test@example.com"
251+-- abc/test%40example.com
252+--
253+linkURI :: Link -> URI
254+linkURI = linkURI' LinkArrayElementBracket
255+
256+-- | How to encode array query elements.
257+data LinkArrayElementStyle
258+ = LinkArrayElementBracket -- ^ @foo[]=1&foo[]=2@
259+ | LinkArrayElementPlain -- ^ @foo=1&foo=2@
260+ deriving (Eq, Ord, Show, Enum, Bounded)
261+
262+-- | Configurable 'linkURI'.
263+--
264+-- >>> type API = "sum" :> QueryParams "x" Int :> Get '[JSON] Int
265+-- >>> linkURI' LinkArrayElementBracket $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API) [1, 2, 3]
266+-- sum?x[]=1&x[]=2&x[]=3
267+--
268+-- >>> linkURI' LinkArrayElementPlain $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API) [1, 2, 3]
269+-- sum?x=1&x=2&x=3
270+--
271+linkURI' :: LinkArrayElementStyle -> Link -> URI
272+linkURI' addBrackets (Link segments q_params) =
273+ URI mempty -- No scheme (relative)
274+ Nothing -- Or authority (relative)
275+ (intercalate "/" $ map getEscaped segments)
276+ (makeQueries q_params) mempty
277+ where
278+ makeQueries :: [Param] -> String
279+ makeQueries [] = ""
280+ makeQueries xs =
281+ "?" <> intercalate "&" (fmap makeQuery xs)
282+
283+ makeQuery :: Param -> String
284+ makeQuery (ArrayElemParam k v) = escape k <> style <> escape (Text.unpack v)
285+ makeQuery (SingleParam k v) = escape k <> "=" <> escape (Text.unpack v)
286+ makeQuery (FlagParam k) = escape k
287+
288+ style = case addBrackets of
289+ LinkArrayElementBracket -> "[]="
290+ LinkArrayElementPlain -> "="
291+
292+escape :: String -> String
293+escape = escapeURIString isUnreserved
294+
295+-- | Create a valid (by construction) relative URI with query params.
296+--
297+-- This function will only typecheck if `endpoint` is part of the API `api`
298+safeLink
299+ :: forall endpoint api. (IsElem endpoint api, HasLink endpoint)
300+ => Proxy api -- ^ The whole API that this endpoint is a part of
301+ -> Proxy endpoint -- ^ The API endpoint you would like to point to
302+ -> MkLink endpoint Link
303+safeLink = safeLink' id
304+
305+-- | More general 'safeLink'.
306+--
307+safeLink'
308+ :: forall endpoint api a. (IsElem endpoint api, HasLink endpoint)
309+ => (Link -> a)
310+ -> Proxy api -- ^ The whole API that this endpoint is a part of
311+ -> Proxy endpoint -- ^ The API endpoint you would like to point to
312+ -> MkLink endpoint a
313+safeLink' toA _ endpoint = toLink toA endpoint (Link mempty mempty)
314+
315+-- | Create all links in an API.
316+--
317+-- Note that the @api@ type must be restricted to the endpoints that have
318+-- valid links to them.
319+--
320+-- >>> type API = "foo" :> Capture "name" Text :> Get '[JSON] Text :<|> "bar" :> Capture "name" Int :> Get '[JSON] Double
321+-- >>> let fooLink :<|> barLink = allLinks (Proxy :: Proxy API)
322+-- >>> :t fooLink
323+-- fooLink :: Text -> Link
324+-- >>> :t barLink
325+-- barLink :: Int -> Link
326+--
327+-- Note: nested APIs don't work well with this approach
328+--
329+-- >>> :kind! MkLink (Capture "nest" Char :> (Capture "x" Int :> Get '[JSON] Int :<|> Capture "y" Double :> Get '[JSON] Double)) Link
330+-- MkLink (Capture "nest" Char :> (Capture "x" Int :> Get '[JSON] Int :<|> Capture "y" Double :> Get '[JSON] Double)) Link :: *
331+-- = Char -> (Int -> Link) :<|> (Double -> Link)
332+allLinks
333+ :: forall api. HasLink api
334+ => Proxy api
335+ -> MkLink api Link
336+allLinks = allLinks' id
337+
338+-- | More general 'allLinks'. See `safeLink'`.
339+allLinks'
340+ :: forall api a. HasLink api
341+ => (Link -> a)
342+ -> Proxy api
343+ -> MkLink api a
344+allLinks' toA api = toLink toA api (Link mempty mempty)
345+
346+-------------------------------------------------------------------------------
347+-- Generics
348+-------------------------------------------------------------------------------
349+
350+-- | Given an API record field, create a link for that route. Only the field's
351+-- type is used.
352+--
353+-- @
354+-- data Record route = Record
355+-- { _get :: route :- Capture "id" Int :> Get '[JSON] String
356+-- , _put :: route :- ReqBody '[JSON] Int :> Put '[JSON] Bool
357+-- }
358+-- deriving ('Generic')
359+--
360+-- getLink :: Int -> Link
361+-- getLink = 'fieldLink' _get
362+-- @
363+--
364+-- @since 0.14.1
365+fieldLink
366+ :: ( IsElem endpoint (ToServantApi routes), HasLink endpoint
367+ , GenericServant routes AsApi
368+ )
369+ => (routes AsApi -> endpoint)
370+ -> MkLink endpoint Link
371+fieldLink = fieldLink' id
372+
373+-- | More general version of 'fieldLink'
374+--
375+-- @since 0.14.1
376+fieldLink'
377+ :: forall routes endpoint a.
378+ ( IsElem endpoint (ToServantApi routes), HasLink endpoint
379+ , GenericServant routes AsApi
380+ )
381+ => (Link -> a)
382+ -> (routes AsApi -> endpoint)
383+ -> MkLink endpoint a
384+fieldLink' toA _ = safeLink' toA (genericApi (Proxy :: Proxy routes)) (Proxy :: Proxy endpoint)
385+
386+-- | A type that specifies that an API record contains a set of links.
387+--
388+-- @since 0.14.1
389+data AsLink (a :: *)
390+instance GenericMode (AsLink a) where
391+ type (AsLink a) :- api = MkLink api a
392+
393+-- | Get all links as a record.
394+--
395+-- @since 0.14.1
396+allFieldLinks
397+ :: ( HasLink (ToServantApi routes)
398+ , GenericServant routes (AsLink Link)
399+ , ToServant routes (AsLink Link) ~ MkLink (ToServantApi routes) Link
400+ )
401+ => routes (AsLink Link)
402+allFieldLinks = allFieldLinks' id
403+
404+-- | More general version of 'allFieldLinks'.
405+--
406+-- @since 0.14.1
407+allFieldLinks'
408+ :: forall routes a.
409+ ( HasLink (ToServantApi routes)
410+ , GenericServant routes (AsLink a)
411+ , ToServant routes (AsLink a) ~ MkLink (ToServantApi routes) a
412+ )
413+ => (Link -> a)
414+ -> routes (AsLink a)
415+allFieldLinks' toA
416+ = fromServant
417+ $ allLinks' toA (Proxy :: Proxy (ToServantApi routes))
418+
419+-------------------------------------------------------------------------------
420+-- HasLink
421+-------------------------------------------------------------------------------
422+
423+-- | Construct a toLink for an endpoint.
424+class HasLink endpoint where
425+ type MkLink endpoint (a :: *)
426+ toLink
427+ :: (Link -> a)
428+ -> Proxy endpoint -- ^ The API endpoint you would like to point to
429+ -> Link
430+ -> MkLink endpoint a
431+
432+-- Naked symbol instance
433+instance (KnownSymbol sym, HasLink sub) => HasLink (sym :> sub) where
434+ type MkLink (sym :> sub) a = MkLink sub a
435+ toLink toA _ =
436+ toLink toA (Proxy :: Proxy sub) . addSegment (escaped seg)
437+ where
438+ seg = symbolVal (Proxy :: Proxy sym)
439+
440+-- QueryParam instances
441+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub, SBoolI (FoldRequired mods))
442+ => HasLink (QueryParam' mods sym v :> sub)
443+ where
444+ type MkLink (QueryParam' mods sym v :> sub) a = If (FoldRequired mods) v (Maybe v) -> MkLink sub a
445+ toLink toA _ l mv =
446+ toLink toA (Proxy :: Proxy sub) $
447+ case sbool :: SBool (FoldRequired mods) of
448+ STrue -> (addQueryParam . SingleParam k . toQueryParam) mv l
449+ SFalse -> maybe id (addQueryParam . SingleParam k . toQueryParam) mv l
450+ where
451+ k :: String
452+ k = symbolVal (Proxy :: Proxy sym)
453+
454+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
455+ => HasLink (QueryParams sym v :> sub)
456+ where
457+ type MkLink (QueryParams sym v :> sub) a = [v] -> MkLink sub a
458+ toLink toA _ l =
459+ toLink toA (Proxy :: Proxy sub) .
460+ foldl' (\l' v -> addQueryParam (ArrayElemParam k (toQueryParam v)) l') l
461+ where
462+ k = symbolVal (Proxy :: Proxy sym)
463+
464+instance (KnownSymbol sym, HasLink sub)
465+ => HasLink (QueryFlag sym :> sub)
466+ where
467+ type MkLink (QueryFlag sym :> sub) a = Bool -> MkLink sub a
468+ toLink toA _ l False =
469+ toLink toA (Proxy :: Proxy sub) l
470+ toLink toA _ l True =
471+ toLink toA (Proxy :: Proxy sub) $ addQueryParam (FlagParam k) l
472+ where
473+ k = symbolVal (Proxy :: Proxy sym)
474+
475+-- :<|> instance - Generate all links at once
476+instance (HasLink a, HasLink b) => HasLink (a :<|> b) where
477+ type MkLink (a :<|> b) r = MkLink a r :<|> MkLink b r
478+ toLink toA _ l = toLink toA (Proxy :: Proxy a) l :<|> toLink toA (Proxy :: Proxy b) l
479+
480+-- Misc instances
481+instance HasLink sub => HasLink (ReqBody' mods ct a :> sub) where
482+ type MkLink (ReqBody' mods ct a :> sub) r = MkLink sub r
483+ toLink toA _ = toLink toA (Proxy :: Proxy sub)
484+
485+instance (ToHttpApiData v, HasLink sub)
486+ => HasLink (Capture' mods sym v :> sub)
487+ where
488+ type MkLink (Capture' mods sym v :> sub) a = v -> MkLink sub a
489+ toLink toA _ l v =
490+ toLink toA (Proxy :: Proxy sub) $
491+ addSegment (escaped . Text.unpack $ toUrlPiece v) l
492+
493+instance (ToHttpApiData v, HasLink sub)
494+ => HasLink (CaptureAll sym v :> sub)
495+ where
496+ type MkLink (CaptureAll sym v :> sub) a = [v] -> MkLink sub a
497+ toLink toA _ l vs = toLink toA (Proxy :: Proxy sub) $
498+ foldl' (flip $ addSegment . escaped . Text.unpack . toUrlPiece) l vs
499+
500+instance HasLink sub => HasLink (Header' mods sym (a :: *) :> sub) where
501+ type MkLink (Header' mods sym a :> sub) r = MkLink sub r
502+ toLink = simpleToLink (Proxy :: Proxy sub)
503+
504+instance HasLink sub => HasLink (Vault :> sub) where
505+ type MkLink (Vault :> sub) a = MkLink sub a
506+ toLink = simpleToLink (Proxy :: Proxy sub)
507+
508+instance HasLink sub => HasLink (Description s :> sub) where
509+ type MkLink (Description s :> sub) a = MkLink sub a
510+ toLink = simpleToLink (Proxy :: Proxy sub)
511+
512+instance HasLink sub => HasLink (Summary s :> sub) where
513+ type MkLink (Summary s :> sub) a = MkLink sub a
514+ toLink = simpleToLink (Proxy :: Proxy sub)
515+
516+instance HasLink sub => HasLink (HttpVersion :> sub) where
517+ type MkLink (HttpVersion:> sub) a = MkLink sub a
518+ toLink = simpleToLink (Proxy :: Proxy sub)
519+
520+instance HasLink sub => HasLink (IsSecure :> sub) where
521+ type MkLink (IsSecure :> sub) a = MkLink sub a
522+ toLink = simpleToLink (Proxy :: Proxy sub)
523+
524+instance HasLink sub => HasLink (WithNamedContext name context sub) where
525+ type MkLink (WithNamedContext name context sub) a = MkLink sub a
526+ toLink toA _ = toLink toA (Proxy :: Proxy sub)
527+
528+instance HasLink sub => HasLink (RemoteHost :> sub) where
529+ type MkLink (RemoteHost :> sub) a = MkLink sub a
530+ toLink = simpleToLink (Proxy :: Proxy sub)
531+
532+instance HasLink sub => HasLink (BasicAuth realm a :> sub) where
533+ type MkLink (BasicAuth realm a :> sub) r = MkLink sub r
534+ toLink = simpleToLink (Proxy :: Proxy sub)
535+
536+instance HasLink EmptyAPI where
537+ type MkLink EmptyAPI a = EmptyAPI
538+ toLink _ _ _ = EmptyAPI
539+
540+-- Verb (terminal) instances
541+instance HasLink (Verb m s ct a) where
542+ type MkLink (Verb m s ct a) r = r
543+ toLink toA _ = toA
544+
545+instance HasLink Raw where
546+ type MkLink Raw a = a
547+ toLink toA _ = toA
548+
549+instance HasLink (Stream m status fr ct a) where
550+ type MkLink (Stream m status fr ct a) r = r
551+ toLink toA _ = toA
552+
553+-- AuthProtext instances
554+instance HasLink sub => HasLink (AuthProtect tag :> sub) where
555+ type MkLink (AuthProtect tag :> sub) a = MkLink sub a
556+ toLink = simpleToLink (Proxy :: Proxy sub)
557+
558+-- | Helper for implemneting 'toLink' for combinators not affecting link
559+-- structure.
560+simpleToLink
561+ :: forall sub a combinator.
562+ (HasLink sub, MkLink sub a ~ MkLink (combinator :> sub) a)
563+ => Proxy sub
564+ -> (Link -> a)
565+ -> Proxy (combinator :> sub)
566+ -> Link
567+ -> MkLink (combinator :> sub) a
568+simpleToLink _ toA _ = toLink toA (Proxy :: Proxy sub)
569+
570+
571+-- $setup
572+-- >>> import Servant.API
573+-- >>> import Data.Text (Text)
servant/src/Servant/Utils/Links.hs+4−485
@@ -1,487 +1,6 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE PolyKinds #-}
7−{-# LANGUAGE ScopedTypeVariables #-}
8−{-# LANGUAGE TypeFamilies #-}
9−{-# LANGUAGE TypeOperators #-}
10−{-# LANGUAGE UndecidableInstances #-}
11−{-# OPTIONS_HADDOCK not-home #-}
12−
13−-- | Type safe generation of internal links.
14−--
15−-- Given an API with a few endpoints:
16−--
17−-- >>> :set -XDataKinds -XTypeFamilies -XTypeOperators
18−-- >>> import Servant.API
19−-- >>> import Servant.Utils.Links
1+module Servant.Utils.Links
20−-- >>> import Data.Proxy
21−-- >>>
22−-- >>> type Hello = "hello" :> Get '[JSON] Int
23−-- >>> type Bye = "bye" :> QueryParam "name" String :> Delete '[JSON] NoContent
24−-- >>> type API = Hello :<|> Bye
25−-- >>> let api = Proxy :: Proxy API
26−--
27−-- It is possible to generate links that are guaranteed to be within 'API' with
28−-- 'safeLink'. The first argument to 'safeLink' is a type representing the API
29−-- you would like to restrict links to. The second argument is the destination
30−-- endpoint you would like the link to point to, this will need to end with a
31−-- verb like GET or POST. Further arguments may be required depending on the
32−-- type of the endpoint. If everything lines up you will get a 'Link' out the
33−-- other end.
34−--
35−-- You may omit 'QueryParam's and the like should you not want to provide them,
36−-- but types which form part of the URL path like 'Capture' must be included.
37−-- The reason you may want to omit 'QueryParam's is that safeLink is a bit
38−-- magical: if parameters are included that could take input it will return a
39−-- function that accepts that input and generates a link. This is best shown
40−-- with an example. Here, a link is generated with no parameters:
41−--
42−-- >>> let hello = Proxy :: Proxy ("hello" :> Get '[JSON] Int)
43−-- >>> toUrlPiece (safeLink api hello :: Link)
44−-- "hello"
45−--
46−-- If the API has an endpoint with parameters then we can generate links with
47−-- or without those:
48−--
49−-- >>> let with = Proxy :: Proxy ("bye" :> QueryParam "name" String :> Delete '[JSON] NoContent)
50−-- >>> toUrlPiece $ safeLink api with (Just "Hubert")
51−-- "bye?name=Hubert"
52−--
53−-- >>> let without = Proxy :: Proxy ("bye" :> Delete '[JSON] NoContent)
54−-- >>> toUrlPiece $ safeLink api without
55−-- "bye"
56−--
57−-- If you would like create a helper for generating links only within that API,
58−-- you can partially apply safeLink if you specify a correct type signature
59−-- like so:
60−--
61−-- >>> :set -XConstraintKinds
62−-- >>> :{
63−-- >>> let apiLink :: (IsElem endpoint API, HasLink endpoint)
64−-- >>> => Proxy endpoint -> MkLink endpoint Link
65−-- >>> apiLink = safeLink api
66−-- >>> :}
67−--
68−-- `safeLink'` allows to make specialise the output:
69−--
70−-- >>> safeLink' toUrlPiece api without
71−-- "bye"
72−--
73−-- >>> :{
74−-- >>> let apiTextLink :: (IsElem endpoint API, HasLink endpoint)
75−-- >>> => Proxy endpoint -> MkLink endpoint Text
76−-- >>> apiTextLink = safeLink' toUrlPiece api
77−-- >>> :}
78−--
79−-- >>> apiTextLink without
80−-- "bye"
81−--
82−-- Attempting to construct a link to an endpoint that does not exist in api
83−-- will result in a type error like this:
84−--
85−-- >>> let bad_link = Proxy :: Proxy ("hello" :> Delete '[JSON] NoContent)
86−-- >>> safeLink api bad_link
87−-- ...
88−-- ...Could not deduce...
89−-- ...
90−--
91−-- This error is essentially saying that the type family couldn't find
92−-- bad_link under api after trying the open (but empty) type family
93−-- `IsElem'` as a last resort.
94−module Servant.Utils.Links (
2+ {-# DEPRECATED "Use Servant.Links." #-}
95− module Servant.API.TypeLevel,
3+ ( module Servant.Links )
96−
97− -- * Building and using safe links
98− --
99− -- | Note that 'URI' is from the "Network.URI" module in the @network-uri@ package.
100− safeLink
101− , safeLink'
102− , allLinks
103− , allLinks'
104− , URI(..)
105− -- * Adding custom types
106− , HasLink(..)
107− , Link
108− , linkURI
109− , linkURI'
110− , LinkArrayElementStyle (..)
111− -- ** Link accessors
112− , Param (..)
113− , linkSegments
114− , linkQueryParams
115−) where
116−
117−import Data.List
118−import Data.Proxy
119− (Proxy (..))
120−import Data.Semigroup
121− ((<>))
122−import Data.Singletons.Bool
123− (SBool (..), SBoolI (..))
124−import qualified Data.Text as Text
125−import qualified Data.Text.Encoding as TE
126−import Data.Type.Bool
127− (If)
128−import GHC.TypeLits
129− (KnownSymbol, symbolVal)
130−import Network.URI
131− (URI (..), escapeURIString, isUnreserved)
132−import Prelude ()
133−import Prelude.Compat
134−
135−import Servant.API.Alternative
136− ((:<|>) ((:<|>)))
137−import Servant.API.BasicAuth
138− (BasicAuth)
139−import Servant.API.Capture
140− (Capture', CaptureAll)
141−import Servant.API.Description
142− (Description, Summary)
143−import Servant.API.Empty
144− (EmptyAPI (..))
145−import Servant.API.Experimental.Auth
146− (AuthProtect)
147−import Servant.API.Header
148− (Header')
149−import Servant.API.HttpVersion
150− (HttpVersion)
151−import Servant.API.IsSecure
152− (IsSecure)
153−import Servant.API.Modifiers
154− (FoldRequired)
155−import Servant.API.QueryParam
156− (QueryFlag, QueryParam', QueryParams)
157−import Servant.API.Raw
158− (Raw)
159−import Servant.API.RemoteHost
160− (RemoteHost)
161−import Servant.API.ReqBody
162− (ReqBody')
163−import Servant.API.Stream
164− (Stream)
165−import Servant.API.Sub
166− (type (:>))
167−import Servant.API.TypeLevel
168−import Servant.API.Vault
169− (Vault)
170−import Servant.API.Verbs
171− (Verb)
172−import Servant.API.WithNamedContext
173− (WithNamedContext)
174−import Web.HttpApiData
175−
176−-- | A safe link datatype.
177−-- The only way of constructing a 'Link' is using 'safeLink', which means any
178−-- 'Link' is guaranteed to be part of the mentioned API.
179−data Link = Link
180− { _segments :: [Escaped]
181− , _queryParams :: [Param]
182− } deriving Show
183−
184−newtype Escaped = Escaped String
185−
186−escaped :: String -> Escaped
187−escaped = Escaped . escapeURIString isUnreserved
188−
189−getEscaped :: Escaped -> String
190−getEscaped (Escaped s) = s
191−
192−instance Show Escaped where
193− showsPrec d (Escaped s) = showsPrec d s
194− show (Escaped s) = show s
195−
196−linkSegments :: Link -> [String]
197−linkSegments = map getEscaped . _segments
198−
199−linkQueryParams :: Link -> [Param]
200−linkQueryParams = _queryParams
201−
202−instance ToHttpApiData Link where
203− toHeader = TE.encodeUtf8 . toUrlPiece
204− toUrlPiece l =
205− let uri = linkURI l
206− in Text.pack $ uriPath uri ++ uriQuery uri
207−
208−-- | Query parameter.
209−data Param
210− = SingleParam String Text.Text
211− | ArrayElemParam String Text.Text
212− | FlagParam String
213− deriving Show
214−
215−addSegment :: Escaped -> Link -> Link
216−addSegment seg l = l { _segments = _segments l <> [seg] }
217−
218−addQueryParam :: Param -> Link -> Link
219−addQueryParam qp l =
220− l { _queryParams = _queryParams l <> [qp] }
221−
222−-- | Transform 'Link' into 'URI'.
223−--
224−-- >>> type API = "something" :> Get '[JSON] Int
225−-- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API)
226−-- something
227−--
228−-- >>> type API = "sum" :> QueryParams "x" Int :> Get '[JSON] Int
229−-- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API) [1, 2, 3]
230−-- sum?x[]=1&x[]=2&x[]=3
231−--
232−-- >>> type API = "foo/bar" :> Get '[JSON] Int
233−-- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API)
234−-- foo%2Fbar
235−--
236−-- >>> type SomeRoute = "abc" :> Capture "email" String :> Put '[JSON] ()
237−-- >>> let someRoute = Proxy :: Proxy SomeRoute
238−-- >>> safeLink someRoute someRoute "test@example.com"
239−-- Link {_segments = ["abc","test%40example.com"], _queryParams = []}
240−--
241−-- >>> linkURI $ safeLink someRoute someRoute "test@example.com"
242−-- abc/test%40example.com
243−--
244−linkURI :: Link -> URI
245−linkURI = linkURI' LinkArrayElementBracket
246−
247−-- | How to encode array query elements.
248−data LinkArrayElementStyle
249− = LinkArrayElementBracket -- ^ @foo[]=1&foo[]=2@
250− | LinkArrayElementPlain -- ^ @foo=1&foo=2@
251− deriving (Eq, Ord, Show, Enum, Bounded)
252−
253−-- | Configurable 'linkURI'.
254−--
255−-- >>> type API = "sum" :> QueryParams "x" Int :> Get '[JSON] Int
256−-- >>> linkURI' LinkArrayElementBracket $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API) [1, 2, 3]
257−-- sum?x[]=1&x[]=2&x[]=3
258−--
259−-- >>> linkURI' LinkArrayElementPlain $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API) [1, 2, 3]
260−-- sum?x=1&x=2&x=3
261−--
262−linkURI' :: LinkArrayElementStyle -> Link -> URI
263−linkURI' addBrackets (Link segments q_params) =
264− URI mempty -- No scheme (relative)
265− Nothing -- Or authority (relative)
266− (intercalate "/" $ map getEscaped segments)
267− (makeQueries q_params) mempty
268 where
4 where
269− makeQueries :: [Param] -> String
270− makeQueries [] = ""
271− makeQueries xs =
272− "?" <> intercalate "&" (fmap makeQuery xs)
273−
274− makeQuery :: Param -> String
275− makeQuery (ArrayElemParam k v) = escape k <> style <> escape (Text.unpack v)
276− makeQuery (SingleParam k v) = escape k <> "=" <> escape (Text.unpack v)
277− makeQuery (FlagParam k) = escape k
278−
279− style = case addBrackets of
280− LinkArrayElementBracket -> "[]="
281− LinkArrayElementPlain -> "="
282−
283−escape :: String -> String
284−escape = escapeURIString isUnreserved
285−
286−-- | Create a valid (by construction) relative URI with query params.
287−--
288−-- This function will only typecheck if `endpoint` is part of the API `api`
289−safeLink
290− :: forall endpoint api. (IsElem endpoint api, HasLink endpoint)
291− => Proxy api -- ^ The whole API that this endpoint is a part of
292− -> Proxy endpoint -- ^ The API endpoint you would like to point to
293− -> MkLink endpoint Link
294−safeLink = safeLink' id
295−
296−-- | More general 'safeLink'.
297−--
298−safeLink'
299− :: forall endpoint api a. (IsElem endpoint api, HasLink endpoint)
300− => (Link -> a)
301− -> Proxy api -- ^ The whole API that this endpoint is a part of
302− -> Proxy endpoint -- ^ The API endpoint you would like to point to
303− -> MkLink endpoint a
304−safeLink' toA _ endpoint = toLink toA endpoint (Link mempty mempty)
305−
306−-- | Create all links in an API.
307−--
308−-- Note that the @api@ type must be restricted to the endpoints that have
309−-- valid links to them.
310−--
311−-- >>> type API = "foo" :> Capture "name" Text :> Get '[JSON] Text :<|> "bar" :> Capture "name" Int :> Get '[JSON] Double
312−-- >>> let fooLink :<|> barLink = allLinks (Proxy :: Proxy API)
313−-- >>> :t fooLink
314−-- fooLink :: Text -> Link
315−-- >>> :t barLink
316−-- barLink :: Int -> Link
317−--
318−-- Note: nested APIs don't work well with this approach
319−--
320−-- >>> :kind! MkLink (Capture "nest" Char :> (Capture "x" Int :> Get '[JSON] Int :<|> Capture "y" Double :> Get '[JSON] Double)) Link
321−-- MkLink (Capture "nest" Char :> (Capture "x" Int :> Get '[JSON] Int :<|> Capture "y" Double :> Get '[JSON] Double)) Link :: *
322−-- = Char -> (Int -> Link) :<|> (Double -> Link)
323−allLinks
324− :: forall api. HasLink api
325− => Proxy api
326− -> MkLink api Link
327−allLinks = allLinks' id
328−
329−-- | More general 'allLinks'. See `safeLink'`.
330−allLinks'
331− :: forall api a. HasLink api
332− => (Link -> a)
333− -> Proxy api
334− -> MkLink api a
335−allLinks' toA api = toLink toA api (Link mempty mempty)
336−
337−-- | Construct a toLink for an endpoint.
338−class HasLink endpoint where
339− type MkLink endpoint (a :: *)
340− toLink
341− :: (Link -> a)
342− -> Proxy endpoint -- ^ The API endpoint you would like to point to
343− -> Link
344− -> MkLink endpoint a
345−
346−-- Naked symbol instance
347−instance (KnownSymbol sym, HasLink sub) => HasLink (sym :> sub) where
348− type MkLink (sym :> sub) a = MkLink sub a
349− toLink toA _ =
350− toLink toA (Proxy :: Proxy sub) . addSegment (escaped seg)
351− where
352− seg = symbolVal (Proxy :: Proxy sym)
353−
354−-- QueryParam instances
355−instance (KnownSymbol sym, ToHttpApiData v, HasLink sub, SBoolI (FoldRequired mods))
356− => HasLink (QueryParam' mods sym v :> sub)
357− where
358− type MkLink (QueryParam' mods sym v :> sub) a = If (FoldRequired mods) v (Maybe v) -> MkLink sub a
359− toLink toA _ l mv =
360− toLink toA (Proxy :: Proxy sub) $
361− case sbool :: SBool (FoldRequired mods) of
362− STrue -> (addQueryParam . SingleParam k . toQueryParam) mv l
363− SFalse -> maybe id (addQueryParam . SingleParam k . toQueryParam) mv l
364− where
365− k :: String
366− k = symbolVal (Proxy :: Proxy sym)
367−
368−instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
369− => HasLink (QueryParams sym v :> sub)
370− where
371− type MkLink (QueryParams sym v :> sub) a = [v] -> MkLink sub a
372− toLink toA _ l =
373− toLink toA (Proxy :: Proxy sub) .
374− foldl' (\l' v -> addQueryParam (ArrayElemParam k (toQueryParam v)) l') l
375− where
376− k = symbolVal (Proxy :: Proxy sym)
377−
378−instance (KnownSymbol sym, HasLink sub)
379− => HasLink (QueryFlag sym :> sub)
380− where
381− type MkLink (QueryFlag sym :> sub) a = Bool -> MkLink sub a
382− toLink toA _ l False =
383− toLink toA (Proxy :: Proxy sub) l
384− toLink toA _ l True =
385− toLink toA (Proxy :: Proxy sub) $ addQueryParam (FlagParam k) l
386− where
387− k = symbolVal (Proxy :: Proxy sym)
388−
389−-- :<|> instance - Generate all links at once
390−instance (HasLink a, HasLink b) => HasLink (a :<|> b) where
391− type MkLink (a :<|> b) r = MkLink a r :<|> MkLink b r
392− toLink toA _ l = toLink toA (Proxy :: Proxy a) l :<|> toLink toA (Proxy :: Proxy b) l
393−
394−-- Misc instances
395−instance HasLink sub => HasLink (ReqBody' mods ct a :> sub) where
396− type MkLink (ReqBody' mods ct a :> sub) r = MkLink sub r
397− toLink toA _ = toLink toA (Proxy :: Proxy sub)
398−
399−instance (ToHttpApiData v, HasLink sub)
400− => HasLink (Capture' mods sym v :> sub)
401− where
402− type MkLink (Capture' mods sym v :> sub) a = v -> MkLink sub a
403− toLink toA _ l v =
404− toLink toA (Proxy :: Proxy sub) $
405− addSegment (escaped . Text.unpack $ toUrlPiece v) l
406−
407−instance (ToHttpApiData v, HasLink sub)
408− => HasLink (CaptureAll sym v :> sub)
409− where
410− type MkLink (CaptureAll sym v :> sub) a = [v] -> MkLink sub a
411− toLink toA _ l vs = toLink toA (Proxy :: Proxy sub) $
412− foldl' (flip $ addSegment . escaped . Text.unpack . toUrlPiece) l vs
413−
414−instance HasLink sub => HasLink (Header' mods sym (a :: *) :> sub) where
415− type MkLink (Header' mods sym a :> sub) r = MkLink sub r
416− toLink = simpleToLink (Proxy :: Proxy sub)
417−
418−instance HasLink sub => HasLink (Vault :> sub) where
419− type MkLink (Vault :> sub) a = MkLink sub a
420− toLink = simpleToLink (Proxy :: Proxy sub)
421−
422−instance HasLink sub => HasLink (Description s :> sub) where
423− type MkLink (Description s :> sub) a = MkLink sub a
424− toLink = simpleToLink (Proxy :: Proxy sub)
425−
426−instance HasLink sub => HasLink (Summary s :> sub) where
427− type MkLink (Summary s :> sub) a = MkLink sub a
428− toLink = simpleToLink (Proxy :: Proxy sub)
429−
430−instance HasLink sub => HasLink (HttpVersion :> sub) where
431− type MkLink (HttpVersion:> sub) a = MkLink sub a
432− toLink = simpleToLink (Proxy :: Proxy sub)
433−
434−instance HasLink sub => HasLink (IsSecure :> sub) where
435− type MkLink (IsSecure :> sub) a = MkLink sub a
436− toLink = simpleToLink (Proxy :: Proxy sub)
437−
438−instance HasLink sub => HasLink (WithNamedContext name context sub) where
439− type MkLink (WithNamedContext name context sub) a = MkLink sub a
440− toLink toA _ = toLink toA (Proxy :: Proxy sub)
441−
442−instance HasLink sub => HasLink (RemoteHost :> sub) where
443− type MkLink (RemoteHost :> sub) a = MkLink sub a
444− toLink = simpleToLink (Proxy :: Proxy sub)
445−
446−instance HasLink sub => HasLink (BasicAuth realm a :> sub) where
447− type MkLink (BasicAuth realm a :> sub) r = MkLink sub r
448− toLink = simpleToLink (Proxy :: Proxy sub)
449−
450−instance HasLink EmptyAPI where
451− type MkLink EmptyAPI a = EmptyAPI
452− toLink _ _ _ = EmptyAPI
453−
454−-- Verb (terminal) instances
455−instance HasLink (Verb m s ct a) where
456− type MkLink (Verb m s ct a) r = r
457− toLink toA _ = toA
458−
459−instance HasLink Raw where
460− type MkLink Raw a = a
461− toLink toA _ = toA
462−
463−instance HasLink (Stream m fr ct a) where
464− type MkLink (Stream m fr ct a) r = r
465− toLink toA _ = toA
466−
467−-- AuthProtext instances
468−instance HasLink sub => HasLink (AuthProtect tag :> sub) where
469− type MkLink (AuthProtect tag :> sub) a = MkLink sub a
470− toLink = simpleToLink (Proxy :: Proxy sub)
471−
472−-- | Helper for implemneting 'toLink' for combinators not affecting link
473−-- structure.
474−simpleToLink
475− :: forall sub a combinator.
476− (HasLink sub, MkLink sub a ~ MkLink (combinator :> sub) a)
477− => Proxy sub
478− -> (Link -> a)
479− -> Proxy (combinator :> sub)
480− -> Link
481− -> MkLink (combinator :> sub) a
482−simpleToLink _ toA _ = toLink toA (Proxy :: Proxy sub)
483−
484
5
485−-- $setup
486−-- >>> import Servant.API
6+import Servant.Links
487−-- >>> import Data.Text (Text)
servant/test/Servant/Utils/LinksSpec.hs → servant/test/Servant/LinksSpec.hsrenamed+3−3
@@ -7,7 +7,7 @@
7#if __GLASGOW_HASKELL__ < 709
7#if __GLASGOW_HASKELL__ < 709
8{-# OPTIONS_GHC -fcontext-stack=41 #-}
8{-# OPTIONS_GHC -fcontext-stack=41 #-}
9#endif
9#endif
10−module Servant.Utils.LinksSpec where
10+module Servant.LinksSpec where
11
11
12import Data.Proxy (Proxy (..))
12import Data.Proxy (Proxy (..))
13import Test.Hspec (Expectation, Spec, describe, it,
13import Test.Hspec (Expectation, Spec, describe, it,
@@ -15,7 +15,7 @@ import Test.Hspec (Expectation, Spec, describe, it,
15import Data.String (fromString)
15import Data.String (fromString)
16
16
17import Servant.API
17import Servant.API
18−import Servant.Utils.Links
18+import Servant.Links
19import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
19import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
20
20
21type TestApi =
21type TestApi =
@@ -51,7 +51,7 @@ shouldBeLink link expected =
51 toUrlPiece link `shouldBe` fromString expected
51 toUrlPiece link `shouldBe` fromString expected
52
52
53spec :: Spec
53spec :: Spec
54−spec = describe "Servant.Utils.Links" $ do
54+spec = describe "Servant.Links" $ do
55 it "generates correct links for capture query params" $ do
55 it "generates correct links for capture query params" $ do
56 let l1 = Proxy :: Proxy ("hello" :> Capture "name" String :> Delete '[JSON] NoContent)
56 let l1 = Proxy :: Proxy ("hello" :> Capture "name" String :> Delete '[JSON] NoContent)
57 apiLink l1 "hi" `shouldBeLink` "hello/hi"
57 apiLink l1 "hi" `shouldBeLink` "hello/hi"
setup.pynew file+11
@@ -0,0 +1,11 @@
1+from setuptools import setup
2+
3+setup(name='servant-rtd',
4+ version='0.0.1',
5+ description='Documentation for the haskell-servant platform',
6+ url='https://github.com/haskell-servant/servant',
7+ author='Servant Contributors',
8+ author_email='haskell-servant-maintainers@googlegroups.com',
9+ license='BSD3',
10+ zip_safe=False)
11+
stack.yaml+1−14
@@ -1,5 +1,5 @@
1# Let's try to keep resolver at the first day of the month
1# Let's try to keep resolver at the first day of the month
2−resolver: nightly-2018-03-01
2+resolver: nightly-2018-06-01
3packages:
3packages:
4- servant-client/
4- servant-client/
5- servant-client-core/
5- servant-client-core/
@@ -8,18 +8,5 @@ packages:
8- servant-server/
8- servant-server/
9- servant/
9- servant/
10
10
11−extra-deps:
12−- cabal-doctest-1.0.6
13−- http-api-data-0.3.7.2
14−- http-types-0.12
15−- text-1.2.3.0
16−- aeson-1.3.0.0
17−- exceptions-0.10.0
18−- aeson-compat-0.3.7.1
19−- free-5.0.1
20−- lens-4.16
21−- random-bytestring-0.1.3
22−- pcg-random-0.1.3.5
23−
24# allow-newer: true # ignores all bounds, that's a sledgehammer
11# allow-newer: true # ignores all bounds, that's a sledgehammer
25# - doc/tutorial/
12# - doc/tutorial/