on master help sign in
Initial commit
commit14468a747a3945af4459713f163fdb13444d2771 authorilyakooo0 <ilyakooo0@gmail.com> dateTue 22 Jan 2019, 16:00 (8 years ago)
17 files changed+1786
.gitignore+190 .swagger-codegen-ignore+23 .travis.yml+9 LICENSE+30 Setup.hs+2 app/Main.hs+10 docs.md+869 docs/Docs.hs+52 package.yaml+81 src/Data/CyclicBuffer.hs+40 src/Data/Error.hs+8 src/Foo/Data.hs+245 src/Lib.hs+98 src/Network/Bacon.hs+39 stack.yaml+64 swagger/Swagger.hs+24 test/Spec.hs+2
.gitignorenew file+190
@@ -0,0 +1,190 @@
1+# Ref: https://gist.github.com/kmorcinek/2710267
2+# Download this file using PowerShell v3 under Windows with the following comand
3+# Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore
4+
5+# User-specific files
6+*.suo
7+*.user
8+*.sln.docstates
9+./nuget
10+
11+# Build results
12+
13+[Dd]ebug/
14+[Rr]elease/
15+x64/
16+build/
17+[Bb]in/
18+[Oo]bj/
19+
20+# NuGet Packages
21+*.nupkg
22+# The packages folder can be ignored because of Package Restore
23+**/packages/*
24+# except build/, which is used as an MSBuild target.
25+!**/packages/build/
26+# Uncomment if necessary however generally it will be regenerated when needed
27+#!**/packages/repositories.config
28+
29+# MSTest test Results
30+[Tt]est[Rr]esult*/
31+[Bb]uild[Ll]og.*
32+
33+*_i.c
34+*_p.c
35+*.ilk
36+*.meta
37+*.obj
38+*.pch
39+*.pdb
40+*.pgc
41+*.pgd
42+*.rsp
43+*.sbr
44+*.tlb
45+*.tli
46+*.tlh
47+*.tmp
48+*.tmp_proj
49+*.log
50+*.vspscc
51+*.vssscc
52+.builds
53+*.pidb
54+*.log
55+*.scc
56+
57+# OS generated files #
58+.DS_Store*
59+ehthumbs.db
60+Icon?
61+Thumbs.db
62+
63+# Visual C++ cache files
64+ipch/
65+*.aps
66+*.ncb
67+*.opensdf
68+*.sdf
69+*.cachefile
70+
71+# Visual Studio profiler
72+*.psess
73+*.vsp
74+*.vspx
75+
76+# Guidance Automation Toolkit
77+*.gpState
78+
79+# ReSharper is a .NET coding add-in
80+_ReSharper*/
81+*.[Rr]e[Ss]harper
82+
83+# TeamCity is a build add-in
84+_TeamCity*
85+
86+# DotCover is a Code Coverage Tool
87+*.dotCover
88+
89+# NCrunch
90+*.ncrunch*
91+.*crunch*.local.xml
92+
93+# Installshield output folder
94+[Ee]xpress/
95+
96+# DocProject is a documentation generator add-in
97+DocProject/buildhelp/
98+DocProject/Help/*.HxT
99+DocProject/Help/*.HxC
100+DocProject/Help/*.hhc
101+DocProject/Help/*.hhk
102+DocProject/Help/*.hhp
103+DocProject/Help/Html2
104+DocProject/Help/html
105+
106+# Click-Once directory
107+publish/
108+
109+# Publish Web Output
110+*.Publish.xml
111+
112+# Windows Azure Build Output
113+csx
114+*.build.csdef
115+
116+# Windows Store app package directory
117+AppPackages/
118+
119+# Others
120+sql/
121+*.Cache
122+ClientBin/
123+[Ss]tyle[Cc]op.*
124+~$*
125+*~
126+*.dbmdl
127+*.[Pp]ublish.xml
128+*.pfx
129+*.publishsettings
130+modulesbin/
131+tempbin/
132+
133+# EPiServer Site file (VPP)
134+AppData/
135+
136+# RIA/Silverlight projects
137+Generated_Code/
138+
139+# Backup & report files from converting an old project file to a newer
140+# Visual Studio version. Backup files are not needed, because we have git ;-)
141+_UpgradeReport_Files/
142+Backup*/
143+UpgradeLog*.XML
144+UpgradeLog*.htm
145+
146+# vim
147+*.txt~
148+*.swp
149+*.swo
150+
151+# svn
152+.svn
153+
154+# SQL Server files
155+**/App_Data/*.mdf
156+**/App_Data/*.ldf
157+**/App_Data/*.sdf
158+
159+
160+#LightSwitch generated files
161+GeneratedArtifacts/
162+_Pvt_Extensions/
163+ModelManifest.xml
164+
165+# =========================
166+# Windows detritus
167+# =========================
168+
169+# Windows image file caches
170+Thumbs.db
171+ehthumbs.db
172+
173+# Folder config file
174+Desktop.ini
175+
176+# Recycle Bin used on file shares
177+$RECYCLE.BIN/
178+
179+# Mac desktop service store files
180+.DS_Store
181+
182+# SASS Compiler cache
183+.sass-cache
184+
185+# Visual Studio 2014 CTP
186+**/*.sln.ide
187+
188+.stack-work
189+.swagger-codegen
190+**.cabal
.swagger-codegen-ignorenew file+23
@@ -0,0 +1,23 @@
1+# Swagger Codegen Ignore
2+# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
3+
4+# Use this file to prevent files from being overwritten by the generator.
5+# The patterns follow closely to .gitignore or .dockerignore.
6+
7+# As an example, the C# client generator defines ApiClient.cs.
8+# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
9+#ApiClient.cs
10+
11+# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+#foo/*/qux
13+# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+#foo/**/qux
17+# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+# You can also negate patterns with an exclamation (!).
20+# For example, you can ignore all files in a docs folder with the file extension .md:
21+#docs/*.md
22+# Then explicitly reverse the ignore rule for a single file:
23+#!docs/README.md
.travis.ymlnew file+9
@@ -0,0 +1,9 @@
1+#
2+# Generated by: https://github.com/swagger-api/swagger-codegen.git
3+#
4+language: csharp
5+mono:
6+ - latest
7+solution: IO.Swagger.sln
8+script:
9+ - /bin/sh ./mono_nunit_test.sh
LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright Author name here (c) 2019
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+
11+ * Redistributions in binary form must reproduce the above
12+ copyright notice, this list of conditions and the following
13+ disclaimer in the documentation and/or other materials provided
14+ with the distribution.
15+
16+ * Neither the name of Author name here nor the names of other
17+ contributors may be used to endorse or promote products derived
18+ from this software without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
app/Main.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+import Network.Wai.Handler.Warp (run)
4+import Servant.Server (serve)
5+import Lib
6+
7+main :: IO ()
8+main = do
9+ srv <- createServer
10+ run 2000 $ serve server srv
docs.mdnew file+869
@@ -0,0 +1,869 @@
1+## GET /posts/:id
2+
3+### Captures:
4+
5+- *id*: The id of the entity you want to query.
6+
7+### Response:
8+
9+- Status code 200
10+- Headers: []
11+
12+- Supported content types are:
13+
14+ - `application/json`
15+
16+- Example (`application/json`):
17+
18+```javascript
19+{
20+ "postBody": "This is the post body",
21+ "postAuthor": 4,
22+ "postId": 1
23+}
24+```
25+
26+- Example (`application/json`):
27+
28+```javascript
29+{
30+ "postBody": "This is another post body",
31+ "postAuthor": 4,
32+ "postId": 1
33+}
34+```
35+
36+- Example (`application/json`):
37+
38+```javascript
39+{
40+ "postBody": "This is the post body",
41+ "postAuthor": 7,
42+ "postId": 1
43+}
44+```
45+
46+- Example (`application/json`):
47+
48+```javascript
49+{
50+ "postBody": "This is another post body",
51+ "postAuthor": 7,
52+ "postId": 1
53+}
54+```
55+
56+- Example (`application/json`):
57+
58+```javascript
59+{
60+ "postBody": "This is the post body",
61+ "postAuthor": 92,
62+ "postId": 1
63+}
64+```
65+
66+## GET /posts/all
67+
68+### Response:
69+
70+- Status code 200
71+- Headers: []
72+
73+- Supported content types are:
74+
75+ - `application/json`
76+
77+- Example (`application/json`):
78+
79+```javascript
80+{
81+ "token": 1,
82+ "reponse": [
83+ {
84+ "postBody": "This is the post body",
85+ "postAuthor": 4,
86+ "postId": 1
87+ },
88+ {
89+ "postBody": "This is another post body",
90+ "postAuthor": 4,
91+ "postId": 1
92+ },
93+ {
94+ "postBody": "This is the post body",
95+ "postAuthor": 7,
96+ "postId": 1
97+ },
98+ {
99+ "postBody": "This is another post body",
100+ "postAuthor": 7,
101+ "postId": 1
102+ },
103+ {
104+ "postBody": "This is the post body",
105+ "postAuthor": 92,
106+ "postId": 1
107+ },
108+ {
109+ "postBody": "This is another post body",
110+ "postAuthor": 92,
111+ "postId": 1
112+ },
113+ {
114+ "postBody": "This is the post body",
115+ "postAuthor": 4,
116+ "postId": 4
117+ },
118+ {
119+ "postBody": "This is another post body",
120+ "postAuthor": 4,
121+ "postId": 4
122+ },
123+ {
124+ "postBody": "This is the post body",
125+ "postAuthor": 7,
126+ "postId": 4
127+ },
128+ {
129+ "postBody": "This is another post body",
130+ "postAuthor": 7,
131+ "postId": 4
132+ },
133+ {
134+ "postBody": "This is the post body",
135+ "postAuthor": 92,
136+ "postId": 4
137+ },
138+ {
139+ "postBody": "This is another post body",
140+ "postAuthor": 92,
141+ "postId": 4
142+ },
143+ {
144+ "postBody": "This is the post body",
145+ "postAuthor": 4,
146+ "postId": 7
147+ },
148+ {
149+ "postBody": "This is another post body",
150+ "postAuthor": 4,
151+ "postId": 7
152+ },
153+ {
154+ "postBody": "This is the post body",
155+ "postAuthor": 7,
156+ "postId": 7
157+ },
158+ {
159+ "postBody": "This is another post body",
160+ "postAuthor": 7,
161+ "postId": 7
162+ },
163+ {
164+ "postBody": "This is the post body",
165+ "postAuthor": 92,
166+ "postId": 7
167+ },
168+ {
169+ "postBody": "This is another post body",
170+ "postAuthor": 92,
171+ "postId": 7
172+ },
173+ {
174+ "postBody": "This is the post body",
175+ "postAuthor": 4,
176+ "postId": 194
177+ },
178+ {
179+ "postBody": "This is another post body",
180+ "postAuthor": 4,
181+ "postId": 194
182+ },
183+ {
184+ "postBody": "This is the post body",
185+ "postAuthor": 7,
186+ "postId": 194
187+ },
188+ {
189+ "postBody": "This is another post body",
190+ "postAuthor": 7,
191+ "postId": 194
192+ },
193+ {
194+ "postBody": "This is the post body",
195+ "postAuthor": 92,
196+ "postId": 194
197+ },
198+ {
199+ "postBody": "This is another post body",
200+ "postAuthor": 92,
201+ "postId": 194
202+ }
203+ ]
204+}
205+```
206+
207+- Example (`application/json`):
208+
209+```javascript
210+{
211+ "token": 46,
212+ "reponse": [
213+ {
214+ "postBody": "This is the post body",
215+ "postAuthor": 4,
216+ "postId": 1
217+ },
218+ {
219+ "postBody": "This is another post body",
220+ "postAuthor": 4,
221+ "postId": 1
222+ },
223+ {
224+ "postBody": "This is the post body",
225+ "postAuthor": 7,
226+ "postId": 1
227+ },
228+ {
229+ "postBody": "This is another post body",
230+ "postAuthor": 7,
231+ "postId": 1
232+ },
233+ {
234+ "postBody": "This is the post body",
235+ "postAuthor": 92,
236+ "postId": 1
237+ },
238+ {
239+ "postBody": "This is another post body",
240+ "postAuthor": 92,
241+ "postId": 1
242+ },
243+ {
244+ "postBody": "This is the post body",
245+ "postAuthor": 4,
246+ "postId": 4
247+ },
248+ {
249+ "postBody": "This is another post body",
250+ "postAuthor": 4,
251+ "postId": 4
252+ },
253+ {
254+ "postBody": "This is the post body",
255+ "postAuthor": 7,
256+ "postId": 4
257+ },
258+ {
259+ "postBody": "This is another post body",
260+ "postAuthor": 7,
261+ "postId": 4
262+ },
263+ {
264+ "postBody": "This is the post body",
265+ "postAuthor": 92,
266+ "postId": 4
267+ },
268+ {
269+ "postBody": "This is another post body",
270+ "postAuthor": 92,
271+ "postId": 4
272+ },
273+ {
274+ "postBody": "This is the post body",
275+ "postAuthor": 4,
276+ "postId": 7
277+ },
278+ {
279+ "postBody": "This is another post body",
280+ "postAuthor": 4,
281+ "postId": 7
282+ },
283+ {
284+ "postBody": "This is the post body",
285+ "postAuthor": 7,
286+ "postId": 7
287+ },
288+ {
289+ "postBody": "This is another post body",
290+ "postAuthor": 7,
291+ "postId": 7
292+ },
293+ {
294+ "postBody": "This is the post body",
295+ "postAuthor": 92,
296+ "postId": 7
297+ },
298+ {
299+ "postBody": "This is another post body",
300+ "postAuthor": 92,
301+ "postId": 7
302+ },
303+ {
304+ "postBody": "This is the post body",
305+ "postAuthor": 4,
306+ "postId": 194
307+ },
308+ {
309+ "postBody": "This is another post body",
310+ "postAuthor": 4,
311+ "postId": 194
312+ },
313+ {
314+ "postBody": "This is the post body",
315+ "postAuthor": 7,
316+ "postId": 194
317+ },
318+ {
319+ "postBody": "This is another post body",
320+ "postAuthor": 7,
321+ "postId": 194
322+ },
323+ {
324+ "postBody": "This is the post body",
325+ "postAuthor": 92,
326+ "postId": 194
327+ },
328+ {
329+ "postBody": "This is another post body",
330+ "postAuthor": 92,
331+ "postId": 194
332+ }
333+ ]
334+}
335+```
336+
337+- Example (`application/json`):
338+
339+```javascript
340+{
341+ "token": 193,
342+ "reponse": [
343+ {
344+ "postBody": "This is the post body",
345+ "postAuthor": 4,
346+ "postId": 1
347+ },
348+ {
349+ "postBody": "This is another post body",
350+ "postAuthor": 4,
351+ "postId": 1
352+ },
353+ {
354+ "postBody": "This is the post body",
355+ "postAuthor": 7,
356+ "postId": 1
357+ },
358+ {
359+ "postBody": "This is another post body",
360+ "postAuthor": 7,
361+ "postId": 1
362+ },
363+ {
364+ "postBody": "This is the post body",
365+ "postAuthor": 92,
366+ "postId": 1
367+ },
368+ {
369+ "postBody": "This is another post body",
370+ "postAuthor": 92,
371+ "postId": 1
372+ },
373+ {
374+ "postBody": "This is the post body",
375+ "postAuthor": 4,
376+ "postId": 4
377+ },
378+ {
379+ "postBody": "This is another post body",
380+ "postAuthor": 4,
381+ "postId": 4
382+ },
383+ {
384+ "postBody": "This is the post body",
385+ "postAuthor": 7,
386+ "postId": 4
387+ },
388+ {
389+ "postBody": "This is another post body",
390+ "postAuthor": 7,
391+ "postId": 4
392+ },
393+ {
394+ "postBody": "This is the post body",
395+ "postAuthor": 92,
396+ "postId": 4
397+ },
398+ {
399+ "postBody": "This is another post body",
400+ "postAuthor": 92,
401+ "postId": 4
402+ },
403+ {
404+ "postBody": "This is the post body",
405+ "postAuthor": 4,
406+ "postId": 7
407+ },
408+ {
409+ "postBody": "This is another post body",
410+ "postAuthor": 4,
411+ "postId": 7
412+ },
413+ {
414+ "postBody": "This is the post body",
415+ "postAuthor": 7,
416+ "postId": 7
417+ },
418+ {
419+ "postBody": "This is another post body",
420+ "postAuthor": 7,
421+ "postId": 7
422+ },
423+ {
424+ "postBody": "This is the post body",
425+ "postAuthor": 92,
426+ "postId": 7
427+ },
428+ {
429+ "postBody": "This is another post body",
430+ "postAuthor": 92,
431+ "postId": 7
432+ },
433+ {
434+ "postBody": "This is the post body",
435+ "postAuthor": 4,
436+ "postId": 194
437+ },
438+ {
439+ "postBody": "This is another post body",
440+ "postAuthor": 4,
441+ "postId": 194
442+ },
443+ {
444+ "postBody": "This is the post body",
445+ "postAuthor": 7,
446+ "postId": 194
447+ },
448+ {
449+ "postBody": "This is another post body",
450+ "postAuthor": 7,
451+ "postId": 194
452+ },
453+ {
454+ "postBody": "This is the post body",
455+ "postAuthor": 92,
456+ "postId": 194
457+ },
458+ {
459+ "postBody": "This is another post body",
460+ "postAuthor": 92,
461+ "postId": 194
462+ }
463+ ]
464+}
465+```
466+
467+- Example (`application/json`):
468+
469+```javascript
470+{
471+ "token": 7,
472+ "reponse": [
473+ {
474+ "postBody": "This is the post body",
475+ "postAuthor": 4,
476+ "postId": 1
477+ },
478+ {
479+ "postBody": "This is another post body",
480+ "postAuthor": 4,
481+ "postId": 1
482+ },
483+ {
484+ "postBody": "This is the post body",
485+ "postAuthor": 7,
486+ "postId": 1
487+ },
488+ {
489+ "postBody": "This is another post body",
490+ "postAuthor": 7,
491+ "postId": 1
492+ },
493+ {
494+ "postBody": "This is the post body",
495+ "postAuthor": 92,
496+ "postId": 1
497+ },
498+ {
499+ "postBody": "This is another post body",
500+ "postAuthor": 92,
501+ "postId": 1
502+ },
503+ {
504+ "postBody": "This is the post body",
505+ "postAuthor": 4,
506+ "postId": 4
507+ },
508+ {
509+ "postBody": "This is another post body",
510+ "postAuthor": 4,
511+ "postId": 4
512+ },
513+ {
514+ "postBody": "This is the post body",
515+ "postAuthor": 7,
516+ "postId": 4
517+ },
518+ {
519+ "postBody": "This is another post body",
520+ "postAuthor": 7,
521+ "postId": 4
522+ },
523+ {
524+ "postBody": "This is the post body",
525+ "postAuthor": 92,
526+ "postId": 4
527+ },
528+ {
529+ "postBody": "This is another post body",
530+ "postAuthor": 92,
531+ "postId": 4
532+ },
533+ {
534+ "postBody": "This is the post body",
535+ "postAuthor": 4,
536+ "postId": 7
537+ },
538+ {
539+ "postBody": "This is another post body",
540+ "postAuthor": 4,
541+ "postId": 7
542+ },
543+ {
544+ "postBody": "This is the post body",
545+ "postAuthor": 7,
546+ "postId": 7
547+ },
548+ {
549+ "postBody": "This is another post body",
550+ "postAuthor": 7,
551+ "postId": 7
552+ },
553+ {
554+ "postBody": "This is the post body",
555+ "postAuthor": 92,
556+ "postId": 7
557+ },
558+ {
559+ "postBody": "This is another post body",
560+ "postAuthor": 92,
561+ "postId": 7
562+ },
563+ {
564+ "postBody": "This is the post body",
565+ "postAuthor": 4,
566+ "postId": 194
567+ },
568+ {
569+ "postBody": "This is another post body",
570+ "postAuthor": 4,
571+ "postId": 194
572+ },
573+ {
574+ "postBody": "This is the post body",
575+ "postAuthor": 7,
576+ "postId": 194
577+ },
578+ {
579+ "postBody": "This is another post body",
580+ "postAuthor": 7,
581+ "postId": 194
582+ },
583+ {
584+ "postBody": "This is the post body",
585+ "postAuthor": 92,
586+ "postId": 194
587+ },
588+ {
589+ "postBody": "This is another post body",
590+ "postAuthor": 92,
591+ "postId": 194
592+ }
593+ ]
594+}
595+```
596+
597+## GET /posts/subscribe/:token
598+
599+### title
600+
601+not title
602+
603+### Captures:
604+
605+- *token*: The token, recieved wit the previuos request
606+
607+### Response:
608+
609+- Status code 200
610+- Headers: []
611+
612+- No response body
613+
614+## GET /users/:id
615+
616+### Captures:
617+
618+- *id*: The id of the entity you want to query.
619+
620+### Response:
621+
622+- Status code 200
623+- Headers: []
624+
625+- Supported content types are:
626+
627+ - `application/json`
628+
629+- Example (`application/json`):
630+
631+```javascript
632+{
633+ "userName": {
634+ "secondName": "Leonidovich",
635+ "firstName": "Seva"
636+ },
637+ "userId": 1
638+}
639+```
640+
641+- Example (`application/json`):
642+
643+```javascript
644+{
645+ "userName": {
646+ "secondName": "Barovich",
647+ "firstName": "Foo"
648+ },
649+ "userId": 42
650+}
651+```
652+
653+- Example (`application/json`):
654+
655+```javascript
656+{
657+ "userName": {
658+ "secondName": "Fooovich",
659+ "firstName": "Bar"
660+ },
661+ "userId": 69
662+}
663+```
664+
665+- Example (`application/json`):
666+
667+```javascript
668+{
669+ "userName": {
670+ "secondName": "Quixovich",
671+ "firstName": "Qux"
672+ },
673+ "userId": 8
674+}
675+```
676+
677+## GET /users/add/:first/:second
678+
679+### Captures:
680+
681+- *first*: The first name of the user.
682+- *second*: The second name of the user.
683+
684+### Response:
685+
686+- Status code 200
687+- Headers: []
688+
689+- Supported content types are:
690+
691+ - `application/json`
692+
693+- Example (`application/json`):
694+
695+```javascript
696+[]
697+```
698+
699+- Example (`application/json`):
700+
701+```javascript
702+[
703+ {
704+ "userName": {
705+ "secondName": "Leonidovich",
706+ "firstName": "Seva"
707+ },
708+ "userId": 1
709+ }
710+]
711+```
712+
713+- Example (`application/json`):
714+
715+```javascript
716+[
717+ {
718+ "userName": {
719+ "secondName": "Leonidovich",
720+ "firstName": "Seva"
721+ },
722+ "userId": 1
723+ },
724+ {
725+ "userName": {
726+ "secondName": "Leonidovich",
727+ "firstName": "Seva"
728+ },
729+ "userId": 1
730+ }
731+]
732+```
733+
734+- Example (`application/json`):
735+
736+```javascript
737+[
738+ {
739+ "userName": {
740+ "secondName": "Barovich",
741+ "firstName": "Foo"
742+ },
743+ "userId": 42
744+ }
745+]
746+```
747+
748+- Example (`application/json`):
749+
750+```javascript
751+[
752+ {
753+ "userName": {
754+ "secondName": "Leonidovich",
755+ "firstName": "Seva"
756+ },
757+ "userId": 1
758+ },
759+ {
760+ "userName": {
761+ "secondName": "Leonidovich",
762+ "firstName": "Seva"
763+ },
764+ "userId": 1
765+ },
766+ {
767+ "userName": {
768+ "secondName": "Leonidovich",
769+ "firstName": "Seva"
770+ },
771+ "userId": 1
772+ }
773+]
774+```
775+
776+## GET /users/all
777+
778+### Response:
779+
780+- Status code 200
781+- Headers: []
782+
783+- Supported content types are:
784+
785+ - `application/json`
786+
787+- Example (`application/json`):
788+
789+```javascript
790+[]
791+```
792+
793+- Example (`application/json`):
794+
795+```javascript
796+[
797+ {
798+ "userName": {
799+ "secondName": "Leonidovich",
800+ "firstName": "Seva"
801+ },
802+ "userId": 1
803+ }
804+]
805+```
806+
807+- Example (`application/json`):
808+
809+```javascript
810+[
811+ {
812+ "userName": {
813+ "secondName": "Leonidovich",
814+ "firstName": "Seva"
815+ },
816+ "userId": 1
817+ },
818+ {
819+ "userName": {
820+ "secondName": "Leonidovich",
821+ "firstName": "Seva"
822+ },
823+ "userId": 1
824+ }
825+]
826+```
827+
828+- Example (`application/json`):
829+
830+```javascript
831+[
832+ {
833+ "userName": {
834+ "secondName": "Barovich",
835+ "firstName": "Foo"
836+ },
837+ "userId": 42
838+ }
839+]
840+```
841+
842+- Example (`application/json`):
843+
844+```javascript
845+[
846+ {
847+ "userName": {
848+ "secondName": "Leonidovich",
849+ "firstName": "Seva"
850+ },
851+ "userId": 1
852+ },
853+ {
854+ "userName": {
855+ "secondName": "Leonidovich",
856+ "firstName": "Seva"
857+ },
858+ "userId": 1
859+ },
860+ {
861+ "userName": {
862+ "secondName": "Leonidovich",
863+ "firstName": "Seva"
864+ },
865+ "userId": 1
866+ }
867+]
868+```
869+
docs/Docs.hsnew file+52
@@ -0,0 +1,52 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE TypeOperators #-}
7+{-# OPTIONS_GHC -fno-warn-orphans #-}
8+
9+-- module Docs where
10+
11+import Lib
12+import Foo.Data
13+import Servant.Docs
14+import Servant.API
15+import qualified Data.Text as T
16+import Servant.Server
17+import Servant
18+import Data.Foldable (fold)
19+import Servant.API.WebSocket
20+import Control.Lens
21+
22+main = writeFile "docs.md" . markdown . docs . pretty $ server
23+
24+-- instance ToSample User
25+instance ToCapture (Capture "first" T.Text) where
26+ toCapture _ = DocCapture "first" "The first name of the user."
27+
28+instance ToSample Foo.Data.Post where
29+ toSamples _ = samples $ Post <$> [1, 4, 7, 194] <*> [4, 7, 92] <*> ["This is the post body", "This is another post body"]
30+
31+instance ToSample User where
32+ toSamples _ = samples [
33+ User (UserName "Seva" "Leonidovich") 1,
34+ User (UserName "Foo" "Barovich") 42,
35+ User (UserName "Bar" "Fooovich") 69,
36+ User (UserName "Qux" "Quixovich") 8]
37+
38+instance ToCapture (Capture "second" T.Text) where
39+ toCapture _ = DocCapture "second" "The second name of the user."
40+
41+instance ToSample (TokenizedResponse [Foo.Data.Post]) where
42+ toSamples _ = samples $ TokenizedResponse <$> [1, 46, 193, 7] <*> [map snd $ toSamples (Proxy :: Proxy Foo.Data.Post)]
43+
44+instance ToCapture (Capture "id" Int) where
45+ toCapture _ = DocCapture "id" "The id of the entity you want to query."
46+
47+instance ToCapture (Capture "token" Int) where
48+ toCapture _ = DocCapture "token" "The token, recieved wit the previuos request"
49+
50+instance HasDocs WebSocketPending where
51+ docsFor Proxy (endpoint, action) =
52+ docsFor (Proxy :: Proxy Raw) (endpoint, action & notes <>~ [DocNote "title" ["not title"]])
package.yamlnew file+81
@@ -0,0 +1,81 @@
1+name: websuck1t
2+version: 0.1.0.0
3+github: "ilyakooo0/websuck1t"
4+
5+extra-source-files:
6+- README.md
7+
8+# Metadata used when publishing your package
9+# synopsis: Short description of your package
10+# category: Web
11+
12+# To avoid duplicated efforts in documentation and dealing with the
13+# complications of embedding Haddock markup inside cabal files, it is
14+# common to point users to the README.md file.
15+description: Please see the README on GitHub at <https://github.com/githubuser/foo#readme>
16+
17+dependencies:
18+- base >= 4.7 && < 5
19+- servant-server
20+- servant
21+- warp
22+- containers
23+- text
24+- aeson
25+- mtl
26+- servant-docs
27+- servant-swagger
28+- swagger2
29+- bytestring
30+- servant-client
31+- http-client
32+- http-client-tls
33+- stm
34+- random
35+# - conduit
36+- servant-websockets
37+- websockets
38+- lens
39+
40+library:
41+ source-dirs: src
42+
43+executables:
44+ websuck1t-exe:
45+ main: Main.hs
46+ source-dirs: app
47+ ghc-options:
48+ - -threaded
49+ - -rtsopts
50+ - -with-rtsopts=-N
51+ dependencies:
52+ - foo
53+ docs-exe:
54+ main: Docs.hs
55+ source-dirs: docs
56+ ghc-options:
57+ - -threaded
58+ - -rtsopts
59+ - -with-rtsopts=-N
60+ dependencies:
61+ - foo
62+ swagger-exe:
63+ main: Swagger.hs
64+ source-dirs: swagger
65+ ghc-options:
66+ - -threaded
67+ - -rtsopts
68+ - -with-rtsopts=-N
69+ dependencies:
70+ - foo
71+
72+tests:
73+ foo-test:
74+ main: Spec.hs
75+ source-dirs: test
76+ ghc-options:
77+ - -threaded
78+ - -rtsopts
79+ - -with-rtsopts=-N
80+ dependencies:
81+ - foo
src/Data/CyclicBuffer.hsnew file+40
@@ -0,0 +1,40 @@
1+module Data.CyclicBuffer
2+ (
3+ empty,
4+ insert,
5+ getFrom,
6+ CyclicBuffer,
7+ lastToken
8+ ) where
9+
10+import Debug.Trace
11+
12+data CyclicBuffer a = CyclicBuffer {
13+ lastId :: Int,
14+ limit :: Int,
15+ elements :: [a]
16+} deriving Show
17+
18+empty :: Int -> CyclicBuffer a
19+empty l = CyclicBuffer 0 l []
20+
21+insert :: CyclicBuffer a -> a -> (Int, CyclicBuffer a)
22+insert (CyclicBuffer last l ee) e = (last+1, CyclicBuffer (last+1) l $ take l (e:ee))
23+
24+getFrom :: CyclicBuffer a -> Int -> Maybe [a]
25+getFrom (CyclicBuffer last limit es) req =
26+ if index < limit && index >= 0
27+ then Just $ take index es
28+ else Nothing
29+ where index = traceShowId $ last - req
30+
31+lastToken :: CyclicBuffer a -> Int
32+lastToken (CyclicBuffer l _ _) = l
33+
34+-- instance Traversable CyclicBuffer where
35+-- traverse f (CyclicBuffer last left es) = CyclicBuffer last left <$> traverse f es
36+
37+-- instance Functor CyclicBuffer where
38+-- fmap f (CyclicBuffer last left es) = CyclicBuffer last left $ map f es
39+
40+-- instance Foldable CyclicBuffer where
src/Data/Error.hsnew file+8
@@ -0,0 +1,8 @@
1+module Data.Error
2+ (
3+
4+ ) where
5+
6+-- data
7+
8+-- data Error
src/Foo/Data.hsnew file+245
@@ -0,0 +1,245 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Foo.Data
5+ (
6+ user,
7+ post,
8+ newUser,
9+ createApp,
10+ createConfig,
11+ User(..),
12+ UserName(..),
13+ Config,
14+ updates,
15+ allUsers,
16+ App,
17+ UserId,
18+ PostId,
19+ Post(..),
20+ allPosts,
21+ addConnection,
22+ removeConnection,
23+ TokenizedResponse(..),
24+ Update(..),
25+ getToken
26+ ) where
27+
28+import GHC.Conc
29+import Control.Concurrent
30+import GHC.Generics
31+import qualified Data.Map.Strict as M
32+import Data.Text (Text, pack)
33+import qualified Data.Text as T
34+import Data.Aeson
35+import Control.Monad
36+import Control.Monad.Reader
37+import Servant.Server
38+import Network.HTTP.Client
39+import Network.HTTP.Client.TLS
40+import Network.Bacon
41+import Data.Bifunctor
42+import Control.Monad.Except
43+import Data.Maybe
44+import Control.Concurrent.STM.TVar
45+import System.Random
46+import Servant.API.WebSocket
47+import Network.WebSockets
48+import qualified Data.Set as S
49+import qualified Data.CyclicBuffer as CB
50+import Data.Set ((\\), union)
51+import Data.Monoid
52+import Debug.Trace
53+
54+type App = ReaderT Config Handler
55+
56+class HasConfig c where
57+ getCfg :: c -> Config
58+
59+allUsers :: App [User]
60+allUsers = ask >>= liftIO . fmap M.elems . readTVarIO . users
61+
62+post :: PostId -> App Post
63+post pId = do
64+ cfg <- ask
65+ u <- liftIO . atomically . fmap (M.lookup pId) . readTVar . posts $ cfg
66+ case u of
67+ Just u -> return u
68+ Nothing -> throwError err404
69+
70+user :: UserId -> App User
71+user uId = do
72+ cfg <- ask
73+ u <- liftIO . atomically . fmap (M.lookup uId) . readTVar . users $ cfg
74+ case u of
75+ Just u -> return u
76+ Nothing -> throwError err404
77+
78+allPosts :: App (STM [Post])
79+allPosts = asks $ fmap M.elems . readTVar . posts
80+
81+getToken :: App (STM Token)
82+getToken = asks $ fmap CB.lastToken . readTVar . updates
83+
84+createConfig :: IO Config
85+createConfig = do
86+ mng <- newManager tlsManagerSettings
87+ cfg <- atomically $ Config <$> newTVar 0 <*> newTVar 0 <*> newTVar M.empty <*> newTVar M.empty <*> return mng <*> newTVar M.empty <*> newTVar 0 <*> newTVar (CB.empty 20)
88+ forkIO . forever $ threadDelay 2000000 >> (runHandler . createApp cfg $ startAddingPosts 20 cfg >>= uncurry sendUpdate)
89+ return cfg
90+
91+type Token = Int
92+
93+data TokenizedResponse d = TokenizedResponse {
94+ token :: Token,
95+ reponse :: d
96+} deriving Generic
97+
98+instance ToJSON d => ToJSON (TokenizedResponse d)
99+
100+data Update = Update {
101+ added :: S.Set PostId,
102+ deleted :: S.Set PostId
103+} deriving (Generic, Show)
104+
105+instance ToJSON Update
106+
107+instance Semigroup Update where
108+ (Update a1 d1) <> (Update a2 d2) = Update added deleted
109+ where
110+ added' = a1 `S.union` a2
111+ deleted' = d1 `S.union` d2
112+ inter = added' `S.intersection` deleted'
113+ added = added' \\ inter
114+ deleted = deleted' \\ inter
115+
116+instance Monoid Update where
117+ mempty = Update S.empty S.empty
118+
119+addConnection :: HasConfig c => c -> Connection -> STM ConnectionId
120+addConnection c conn = do
121+ let cfg = getCfg c
122+ lastID <- fmap (+1) . readTVar . lastConnection $ cfg
123+ flip writeTVar lastID . lastConnection $ cfg
124+ modifyTVar (connections cfg) $ M.insert lastID conn
125+ return lastID
126+
127+removeConnection :: HasConfig c => c -> ConnectionId -> STM ()
128+removeConnection c cId = do
129+ let cfg = getCfg c
130+ modifyTVar (connections cfg) $ M.delete cId
131+
132+
133+
134+createApp :: (HasConfig c) => c -> ReaderT Config Handler a -> Handler a
135+createApp = flip runReaderT . getCfg
136+
137+type UserId = Int
138+type PostId = Int
139+type ConnectionId = Int
140+
141+data Config = Config {
142+ lastUserID :: TVar UserId,
143+ lastPostID :: TVar PostId,
144+ users :: TVar (M.Map Int User),
145+ posts :: TVar (M.Map Int Post),
146+ manager :: Manager,
147+ connections :: TVar (M.Map ConnectionId Connection),
148+ lastConnection :: TVar ConnectionId,
149+ updates :: TVar (CB.CyclicBuffer Update)
150+}
151+
152+instance HasConfig Config where
153+ getCfg = id
154+
155+-- startAddingUsers :: Config -> App ()
156+-- startAddingUsers cfg = do
157+-- a <- liftIO $ loremBacon (manager cfg) (Just AllMeat) (Just 2) (Just False)
158+-- let t = fromMaybe ["None", "None"] a
159+-- liftIO . atomically $ newUser cfg (t !! 0) (t !! 1)
160+-- return ()
161+
162+startAddingPosts :: Int -> Config -> App (Token, Update)
163+startAddingPosts lim cfg = do
164+ cfg <- ask
165+ let us = users cfg
166+ let ps = posts cfg
167+
168+ a <- liftIO $ loremBacon (manager cfg) (Just AllMeat) (Just lim) (Just False)
169+ g <- liftIO newStdGen
170+ let rns = randoms g
171+
172+ let t = fromMaybe (repeat "None") a
173+ liftIO . atomically $ do
174+ uu <- readTVar us
175+ let uSize = M.size uu
176+ if uSize >= 1 then do
177+ pp <- readTVar ps
178+ let toDeleteIndex = head rns `mod` M.size pp
179+ let deletedKey = fst $ M.elemAt toDeleteIndex pp
180+ dd <- if M.size pp > 0 then writeTVar ps (M.deleteAt toDeleteIndex pp) >> return [deletedKey]
181+ else return []
182+ let toAdd = max 0 $ lim - (M.size pp - 1)
183+ add <- fmap (map postId) $ forM (zip rns $ take toAdd t) $ \(rnd, t) -> newPost cfg (randomFrom rnd uu) t
184+ let upd = Update (S.fromList add) (S.fromList dd)
185+ let uppT = updates cfg
186+ upp <- readTVar uppT
187+ let (token, upp') = CB.insert upp upd
188+ writeTVar uppT upp'
189+ return (token, upd)
190+ else return (0, mempty)
191+
192+sendUpdate :: Token -> Update -> App ()
193+sendUpdate t u = do
194+ cfg <- ask
195+ conns <- fmap M.elems . liftIO . readTVarIO $ connections cfg
196+ liftIO $ forM conns $ flip sendTextData $ encode $ TokenizedResponse t u
197+ return ()
198+
199+randomFrom :: Int -> M.Map k v -> k
200+randomFrom g as = M.keys as !! (abs g `mod` M.size as)
201+
202+newUser :: Config -> Text -> Text -> STM User
203+newUser cfg first second = do
204+ let lastID = lastUserID cfg
205+ let us = users cfg
206+ do
207+ id <- readTVar lastID
208+ writeTVar lastID (id+1)
209+ let user = User (UserName first second) id
210+ oldUsers <- readTVar us
211+ writeTVar us $ M.insert id user oldUsers
212+ return user
213+
214+newPost :: Config -> UserId -> Text -> STM Post
215+newPost cfg user body = do
216+ let lastId = lastPostID cfg
217+ let ps = posts cfg
218+ do
219+ id <- readTVar lastId
220+ writeTVar lastId (id+1)
221+ let p = Post id user body
222+ modifyTVar ps $ M.insert id p
223+ return p
224+
225+data User = User {
226+ userName :: UserName,
227+ userId :: UserId
228+} deriving Generic
229+
230+data Post = Post {
231+ postId :: PostId,
232+ postAuthor :: UserId,
233+ postBody :: Text
234+} deriving Generic
235+
236+instance ToJSON User
237+instance ToJSON Post
238+
239+data UserName = UserName {
240+ firstName :: Text,
241+ secondName :: Text
242+} deriving (Generic)
243+
244+instance ToJSON UserName
245+
src/Lib.hsnew file+98
@@ -0,0 +1,98 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+module Lib
6+ ( server,
7+ createServer
8+
9+ ) where
10+
11+import Data.Proxy
12+import Servant.API
13+import Servant
14+import GHC.Conc
15+import Control.Monad.IO.Class
16+import System.IO
17+import Foo.Data as D
18+import Data.Text
19+import Control.Monad.Reader
20+import Network.Bacon
21+import Servant.API.WebSocket
22+import Network.WebSockets
23+import Control.Monad (forever)
24+import Control.Exception (finally)
25+import Data.Aeson
26+import qualified Data.Set as S
27+import Data.CyclicBuffer
28+import Data.Foldable (fold)
29+
30+
31+type API = "users" :> Capture "id" UserId :> Get '[JSON] User
32+ :<|> "users" :> "add" :> Capture "first" Text :> Capture "second" Text :> Get '[JSON] [User]
33+ :<|> "users" :> "all" :> Get '[JSON] [User]
34+ :<|> "posts" :> Capture "id" PostId :> Get '[JSON] D.Post
35+ :<|> "posts" :> "all" :> Get '[JSON] (TokenizedResponse [D.Post])
36+ :<|> "posts" :> "subscribe" :> Capture "token" Int :> WebSocketPending
37+
38+createServer :: IO (Server API)
39+createServer = do
40+ cfg <- createConfig
41+ atomically $ newUser cfg "Kostya" "Designer"
42+ return $ hoistServer server (createApp cfg) serverAPI
43+
44+server :: Proxy API
45+server = Proxy
46+
47+serverAPI :: ServerT API App
48+serverAPI =
49+ user
50+ :<|> createUserPath
51+ :<|> allUsers
52+ :<|> post
53+ :<|> returnPosts
54+ :<|> validateConnection
55+
56+createUserPath :: Text -> Text -> App [User]
57+createUserPath first second = do
58+ cfg <- ask
59+ liftIO . atomically $ newUser cfg first second
60+ allUsers
61+
62+returnPosts :: App (TokenizedResponse [D.Post])
63+returnPosts = do
64+ posts <- allPosts
65+ t <- getToken
66+ liftIO $ atomically $ TokenizedResponse <$> t <*> posts
67+
68+invalidTokenError :: RejectRequest
69+invalidTokenError = defaultRejectRequest {
70+ rejectCode = 498,
71+ rejectMessage = "The supplied token is not valid" }
72+
73+validateConnection :: Int -> PendingConnection -> App ()
74+validateConnection t pc = do
75+ cfg <- ask
76+ (cyc, token) <- liftIO $ atomically $ do
77+ uu <- readTVar $ updates cfg
78+ return (getFrom uu t, lastToken uu)
79+ case cyc of
80+ Nothing -> liftIO $ rejectRequestWith pc invalidTokenError
81+ Just uu -> do
82+ conn <- liftIO $ acceptRequest pc
83+ liftIO $ sendTextData conn $ encode $ TokenizedResponse token $ fold uu
84+ subscribe conn
85+ return ()
86+
87+subscribe :: Connection -> App ()
88+subscribe conn = do
89+ cfg <- ask
90+ cId <- liftSTM $ addConnection cfg conn
91+ -- liftIO $ sendDataMessage conn . Binary . encode $ D.TokenizedResponse 1 (Update (S.fromList [1, 2, 3]) (S.fromList [4, 2,6]))
92+ liftIO $ flip finally (atomically $ removeConnection cfg cId) $ forever $ do
93+ _ <- receiveDataMessage conn
94+ return ()
95+ return ()
96+
97+liftSTM :: MonadIO m => STM a -> m a
98+liftSTM = liftIO . atomically
src/Network/Bacon.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+module Network.Bacon (
6+ loremBacon,
7+ LoremType(..)
8+) where
9+
10+
11+import Servant.Client
12+import Servant.API
13+import Data.Text
14+import Servant
15+import Network.HTTP.Client (Manager)
16+import Data.Bifunctor
17+
18+data LoremType = MeatAndFiller | AllMeat
19+
20+instance ToHttpApiData LoremType where
21+ toQueryParam MeatAndFiller = "meat-and-filler"
22+ toQueryParam AllMeat = "all-meat"
23+
24+type API = QueryParam "type" LoremType :> QueryParam "paras" Int :> QueryParam "start-with-lorem" Bool :> Get '[JSON] [Text]
25+
26+clientAPI :: Proxy API
27+clientAPI = Proxy
28+
29+loremBacon' :: Maybe LoremType -> Maybe Int -> Maybe Bool -> ClientM [Text]
30+loremBacon' = client clientAPI
31+
32+loremBacon :: Manager -> Maybe LoremType -> Maybe Int -> Maybe Bool -> IO (Maybe [Text])
33+loremBacon mng a b c = do
34+ let env = mkClientEnv mng (BaseUrl Https "baconipsum.com" 443 "api")
35+ res <- runClientM (loremBacon' a b c) env
36+ return $ case res of
37+ Left _ -> Nothing
38+ Right a -> Just a
39+ -- return . pack . show $ res
stack.yamlnew file+64
@@ -0,0 +1,64 @@
1+# This file was automatically generated by 'stack init'
2+#
3+# Some commonly used options have been documented as comments in this file.
4+# For advanced use and comprehensive documentation of the format, please see:
5+# https://docs.haskellstack.org/en/stable/yaml_configuration/
6+
7+# Resolver to choose a 'specific' stackage snapshot or a compiler version.
8+# A snapshot resolver dictates the compiler version and the set of packages
9+# to be used for project dependencies. For example:
10+#
11+# resolver: lts-3.5
12+# resolver: nightly-2015-09-21
13+# resolver: ghc-7.10.2
14+#
15+# The location of a snapshot can be provided as a file or url. Stack assumes
16+# a snapshot provided as a file might change, whereas a url resource does not.
17+#
18+# resolver: ./custom-snapshot.yaml
19+# resolver: https://example.com/snapshots/2018-01-01.yaml
20+resolver: lts-13.1
21+
22+# User packages to be built.
23+# Various formats can be used as shown in the example below.
24+#
25+# packages:
26+# - some-directory
27+# - https://example.com/foo/bar/baz-0.0.2.tar.gz
28+# - location:
29+# git: https://github.com/commercialhaskell/stack.git
30+# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
31+# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
32+# subdirs:
33+# - auto-update
34+# - wai
35+packages:
36+- .
37+# Dependency packages to be pulled from upstream that are not in the resolver
38+# using the same syntax as the packages field.
39+# (e.g., acme-missiles-0.3)
40+# extra-deps: []
41+
42+# Override default flag values for local packages and extra-deps
43+# flags: {}
44+
45+# Extra package databases containing global packages
46+# extra-package-dbs: []
47+
48+# Control whether we use the GHC we find on the path
49+# system-ghc: true
50+#
51+# Require a specific version of stack, using version ranges
52+# require-stack-version: -any # Default
53+# require-stack-version: ">=1.9"
54+#
55+# Override the architecture used by stack, especially useful on Windows
56+# arch: i386
57+# arch: x86_64
58+#
59+# Extra directories used by stack for building
60+# extra-include-dirs: [/path/to/dir]
61+# extra-lib-dirs: [/path/to/dir]
62+#
63+# Allow a newer minor version of GHC than the snapshot specifies
64+# compiler-check: newer-minor
swagger/Swagger.hsnew file+24
@@ -0,0 +1,24 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE TypeOperators #-}
7+{-# OPTIONS_GHC -fno-warn-orphans #-}
8+
9+-- module Docs where
10+
11+import Lib
12+import Foo.Data
13+import Data.Swagger
14+import Servant.Swagger
15+import Servant.API
16+import Data.Text
17+import Servant.Server
18+import Data.Aeson
19+import qualified Data.ByteString.Lazy as BS
20+
21+instance ToSchema User
22+instance ToSchema UserName
23+
24+main = return () -- BS.writeFile "swag.txt" . encode . toSwagger $ server
test/Spec.hsnew file+2
@@ -0,0 +1,2 @@
1+main :: IO ()
2+main = putStrLn "Test suite not yet implemented"