Skip to content

Commit 0024f61

Browse files
committed
WIP: consolidate APIs
1 parent 2673bd4 commit 0024f61

File tree

6 files changed

+94
-92
lines changed

6 files changed

+94
-92
lines changed

src/HTTPure.purs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import HTTPure.Response
2020
( Response
2121
, ResponseM
2222
, response, response'
23-
, binaryResponse, binaryResponse'
2423
, emptyResponse, emptyResponse'
2524

2625
-- 1xx

src/HTTPure/Body.purs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
module HTTPure.Body
2-
( Body(..)
2+
( class Body
33
, read
4-
, write
54
, size
5+
, write
66
) where
77

88
import Prelude
99

1010
import Data.Either as Either
11+
import Data.Maybe as Maybe
12+
import Data.String as String
1113
import Effect as Effect
1214
import Effect.Aff as Aff
1315
import Effect.Ref as Ref
14-
import Node.Buffer as Buffer
1516
import Node.Encoding as Encoding
1617
import Node.HTTP as HTTP
1718
import Node.Stream as Stream
1819

19-
-- | The `Body` type is just sugar for a `String`, that will be sent or received
20-
-- | in the HTTP body.
21-
data Body
22-
= StringBody String
23-
| BinaryBody Buffer.Buffer
20+
import HTTPure.Streamable as Streamable
21+
22+
class Streamable.Streamable b <= Body b where
23+
size :: b -> Effect.Effect (Maybe.Maybe Int)
24+
25+
instance bodyString :: Body String where
26+
size s = pure $ Maybe.Just $ String.length s
2427

2528
-- | Extract the contents of the body of the HTTP `Request`.
2629
read :: HTTP.Request -> Aff.Aff String
@@ -33,18 +36,5 @@ read request = Aff.makeAff \done -> do
3336
pure $ Aff.nonCanceler
3437

3538
-- | Write a `Body` to the given HTTP `Response` and close it.
36-
write :: HTTP.Response -> Body -> Effect.Effect Unit
37-
write response body = void do
38-
_ <- writeToStream $ pure unit
39-
Stream.end stream $ pure unit
40-
where
41-
stream = HTTP.responseAsStream response
42-
writeToStream =
43-
case body of
44-
StringBody str -> Stream.writeString stream Encoding.UTF8 str
45-
BinaryBody buf -> Stream.write stream buf
46-
47-
-- | Get the size of the body in bytes
48-
size :: Body -> Effect.Effect Int
49-
size (StringBody body) = Buffer.fromString body Encoding.UTF8 >>= Buffer.size
50-
size (BinaryBody body) = Buffer.size body
39+
write :: HTTP.Response -> Stream.Readable () -> Effect.Effect Unit
40+
write response body = void $ Stream.pipe body $ HTTP.responseAsStream response

src/HTTPure/Response.purs

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module HTTPure.Response
33
, ResponseM
44
, send
55
, response, response'
6-
, binaryResponse, binaryResponse'
76
, emptyResponse, emptyResponse'
87

98
-- 1xx
@@ -79,14 +78,17 @@ module HTTPure.Response
7978

8079
import Prelude
8180

81+
import Data.Maybe as Maybe
8282
import Effect as Effect
8383
import Effect.Aff as Aff
84-
import Node.Buffer as Buffer
84+
import Effect.Class as EffectClass
8585
import Node.HTTP as HTTP
86+
import Node.Stream as Stream
8687

8788
import HTTPure.Body as Body
8889
import HTTPure.Headers as Headers
8990
import HTTPure.Status as Status
91+
import HTTPure.Streamable as Streamable
9092

9193
-- | The `ResponseM` type simply conveniently wraps up an HTTPure monad that
9294
-- | returns a response. This type is the return type of all router/route
@@ -97,53 +99,44 @@ type ResponseM = Aff.Aff Response
9799
type Response =
98100
{ status :: Status.Status
99101
, headers :: Headers.Headers
100-
, body :: Body.Body
102+
, body :: Stream.Readable ()
103+
, size :: Maybe.Maybe Int
101104
}
102105

103106
-- | Given an HTTP `Response` and a HTTPure `Response`, this method will return
104107
-- | a monad encapsulating writing the HTTPure `Response` to the HTTP `Response`
105108
-- | and closing the HTTP `Response`.
106109
send :: HTTP.Response -> Response -> Effect.Effect Unit
107-
send httpresponse { status, headers, body } = do
110+
send httpresponse { status, headers, body, size } = do
108111
Status.write httpresponse $ status
109-
size <- Body.size body
110112
Headers.write httpresponse $ headers <> contentLength size
111113
Body.write httpresponse $ body
112114
where
113-
contentLength size = Headers.header "Content-Length" $ show size
115+
contentLength (Maybe.Just s) = Headers.header "Content-Length" $ show s
116+
contentLength Maybe.Nothing = Headers.empty
114117

115118
-- | For custom response statuses or providing a body for response codes that
116119
-- | don't typically send one.
117-
response :: Status.Status -> String -> ResponseM
120+
response :: forall b. Body.Body b => Status.Status -> b -> ResponseM
118121
response status = response' status Headers.empty
119122

120123
-- | The same as `response` but with headers.
121-
response' :: Status.Status ->
124+
response' :: forall b. Body.Body b =>
125+
Status.Status ->
122126
Headers.Headers ->
123-
String ->
127+
b ->
124128
ResponseM
125-
response' status headers body =
126-
pure $ { status, headers, body: Body.StringBody body }
127-
128-
-- | Like `response`, but the response body is binary data.
129-
binaryResponse :: Status.Status -> Buffer.Buffer -> Aff.Aff Response
130-
binaryResponse status = binaryResponse' status Headers.empty
131-
132-
-- | The same as `binaryResponse` but with headers.
133-
binaryResponse' :: Status.Status ->
134-
Headers.Headers ->
135-
Buffer.Buffer ->
136-
Aff.Aff Response
137-
binaryResponse' status headers body
138-
= pure $ { status, headers, body: Body.BinaryBody body }
129+
response' status headers body = do
130+
size <- EffectClass.liftEffect $ Body.size body
131+
pure $ { status , headers , size , body: Streamable.toStream body }
139132

140133
-- | The same as `response` but without a body.
141134
emptyResponse :: Status.Status -> ResponseM
142135
emptyResponse status = emptyResponse' status Headers.empty
143136

144137
-- | The same as `emptyResponse` but with headers.
145138
emptyResponse' :: Status.Status -> Headers.Headers -> ResponseM
146-
emptyResponse' status headers = response' status headers ""
139+
emptyResponse' status headers = response' status headers $ ""
147140

148141
---------
149142
-- 1xx --
@@ -178,11 +171,11 @@ processing' = emptyResponse' Status.processing
178171
---------
179172

180173
-- | 200
181-
ok :: String -> ResponseM
174+
ok :: forall b. Body.Body b => b -> ResponseM
182175
ok = ok' Headers.empty
183176

184177
-- | 200 with headers
185-
ok' :: Headers.Headers -> String -> ResponseM
178+
ok' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
186179
ok' = response' Status.ok
187180

188181
-- | 201
@@ -202,12 +195,13 @@ accepted' :: Headers.Headers -> ResponseM
202195
accepted' = emptyResponse' Status.accepted
203196

204197
-- | 203
205-
nonAuthoritativeInformation :: String -> ResponseM
198+
nonAuthoritativeInformation :: forall b. Body.Body b => b -> ResponseM
206199
nonAuthoritativeInformation = nonAuthoritativeInformation' Headers.empty
207200

208201
-- | 203 with headers
209-
nonAuthoritativeInformation' :: Headers.Headers ->
210-
String ->
202+
nonAuthoritativeInformation' :: forall b. Body.Body b =>
203+
Headers.Headers ->
204+
b ->
211205
ResponseM
212206
nonAuthoritativeInformation' = response' Status.nonAuthoritativeInformation
213207

@@ -228,19 +222,19 @@ resetContent' :: Headers.Headers -> ResponseM
228222
resetContent' = emptyResponse' Status.resetContent
229223

230224
-- | 206
231-
partialContent :: String -> ResponseM
225+
partialContent :: forall b. Body.Body b => b -> ResponseM
232226
partialContent = partialContent' Headers.empty
233227

234228
-- | 206 with headers
235-
partialContent' :: Headers.Headers -> String -> ResponseM
229+
partialContent' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
236230
partialContent' = response' Status.partialContent
237231

238232
-- | 207
239-
multiStatus :: String -> ResponseM
233+
multiStatus :: forall b. Body.Body b => b -> ResponseM
240234
multiStatus = multiStatus' Headers.empty
241235

242236
-- | 207 with headers
243-
multiStatus' :: Headers.Headers -> String -> ResponseM
237+
multiStatus' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
244238
multiStatus' = response' Status.multiStatus
245239

246240
-- | 208
@@ -252,47 +246,47 @@ alreadyReported' :: Headers.Headers -> ResponseM
252246
alreadyReported' = emptyResponse' Status.alreadyReported
253247

254248
-- | 226
255-
iMUsed :: String -> ResponseM
249+
iMUsed :: forall b. Body.Body b => b -> ResponseM
256250
iMUsed = iMUsed' Headers.empty
257251

258252
-- | 226 with headers
259-
iMUsed' :: Headers.Headers -> String -> ResponseM
253+
iMUsed' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
260254
iMUsed' = response' Status.iMUsed
261255

262256
---------
263257
-- 3xx --
264258
---------
265259

266260
-- | 300
267-
multipleChoices :: String -> ResponseM
261+
multipleChoices :: forall b. Body.Body b => b -> ResponseM
268262
multipleChoices = multipleChoices' Headers.empty
269263

270264
-- | 300 with headers
271-
multipleChoices' :: Headers.Headers -> String -> ResponseM
265+
multipleChoices' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
272266
multipleChoices' = response' Status.multipleChoices
273267

274268
-- | 301
275-
movedPermanently :: String -> ResponseM
269+
movedPermanently :: forall b. Body.Body b => b -> ResponseM
276270
movedPermanently = movedPermanently' Headers.empty
277271

278272
-- | 301 with headers
279-
movedPermanently' :: Headers.Headers -> String -> ResponseM
273+
movedPermanently' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
280274
movedPermanently' = response' Status.movedPermanently
281275

282276
-- | 302
283-
found :: String -> ResponseM
277+
found :: forall b. Body.Body b => b -> ResponseM
284278
found = found' Headers.empty
285279

286280
-- | 302 with headers
287-
found' :: Headers.Headers -> String -> ResponseM
281+
found' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
288282
found' = response' Status.found
289283

290284
-- | 303
291-
seeOther :: String -> ResponseM
285+
seeOther :: forall b. Body.Body b => b -> ResponseM
292286
seeOther = seeOther' Headers.empty
293287

294288
-- | 303 with headers
295-
seeOther' :: Headers.Headers -> String -> ResponseM
289+
seeOther' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
296290
seeOther' = response' Status.seeOther
297291

298292
-- | 304
@@ -304,27 +298,27 @@ notModified' :: Headers.Headers -> ResponseM
304298
notModified' = emptyResponse' Status.notModified
305299

306300
-- | 305
307-
useProxy :: String -> ResponseM
301+
useProxy :: forall b. Body.Body b => b -> ResponseM
308302
useProxy = useProxy' Headers.empty
309303

310304
-- | 305 with headers
311-
useProxy' :: Headers.Headers -> String -> ResponseM
305+
useProxy' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
312306
useProxy' = response' Status.useProxy
313307

314308
-- | 307
315-
temporaryRedirect :: String -> ResponseM
309+
temporaryRedirect :: forall b. Body.Body b => b -> ResponseM
316310
temporaryRedirect = temporaryRedirect' Headers.empty
317311

318312
-- | 307 with headers
319-
temporaryRedirect' :: Headers.Headers -> String -> ResponseM
313+
temporaryRedirect' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
320314
temporaryRedirect' = response' Status.temporaryRedirect
321315

322316
-- | 308
323-
permanentRedirect :: String -> ResponseM
317+
permanentRedirect :: forall b. Body.Body b => b -> ResponseM
324318
permanentRedirect = permanentRedirect' Headers.empty
325319

326320
-- | 308 with headers
327-
permanentRedirect' :: Headers.Headers -> String -> ResponseM
321+
permanentRedirect' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
328322
permanentRedirect' = response' Status.permanentRedirect
329323

330324

@@ -333,11 +327,11 @@ permanentRedirect' = response' Status.permanentRedirect
333327
---------
334328

335329
-- | 400
336-
badRequest :: String -> ResponseM
330+
badRequest :: forall b. Body.Body b => b -> ResponseM
337331
badRequest = badRequest' Headers.empty
338332

339333
-- | 400 with headers
340-
badRequest' :: Headers.Headers -> String -> ResponseM
334+
badRequest' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
341335
badRequest' = response' Status.badRequest
342336

343337
-- | 401
@@ -405,11 +399,11 @@ requestTimeout' :: Headers.Headers -> ResponseM
405399
requestTimeout' = emptyResponse' Status.requestTimeout
406400

407401
-- | 409
408-
conflict :: String -> ResponseM
402+
conflict :: forall b. Body.Body b => b -> ResponseM
409403
conflict = conflict' Headers.empty
410404

411405
-- | 409 with headers
412-
conflict' :: Headers.Headers -> String -> ResponseM
406+
conflict' :: forall b. Body.Body b => Headers.Headers -> b -> ResponseM
413407
conflict' = response' Status.conflict
414408

415409
-- | 410
@@ -561,11 +555,14 @@ unavailableForLegalReasons' = emptyResponse' Status.unavailableForLegalReasons
561555
---------
562556

563557
-- | 500
564-
internalServerError :: String -> ResponseM
558+
internalServerError :: forall b. Body.Body b => b -> ResponseM
565559
internalServerError = internalServerError' Headers.empty
566560

567561
-- | 500 with headers
568-
internalServerError' :: Headers.Headers -> String -> ResponseM
562+
internalServerError' :: forall b. Body.Body b =>
563+
Headers.Headers ->
564+
b ->
565+
ResponseM
569566
internalServerError' = response' Status.internalServerError
570567

571568
-- | 501

src/HTTPure/Streamable.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"use strict";
2+
3+
exports.createStreamFromString = function (str) {
4+
var stream = new require('stream').Readable();
5+
stream._read = function () {};
6+
stream.push(str);
7+
stream.push(null);
8+
return stream;
9+
}

src/HTTPure/Streamable.purs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module HTTPure.Streamable
2+
( class Streamable
3+
, toStream
4+
) where
5+
6+
import Node.Stream as Stream
7+
8+
foreign import createStreamFromString :: String -> Stream.Readable ()
9+
10+
class Streamable s where
11+
toStream :: s -> Stream.Readable ()
12+
13+
instance streamableString :: Streamable String where
14+
toStream = createStreamFromString

0 commit comments

Comments
 (0)