@@ -332,13 +332,101 @@ namespace internal {
332
332
/// The Request body is buffered, the response is streaming (as far
333
333
/// as the backend implementation allows).
334
334
def request[R]{ body: => Unit / RequestBuilder }{ res: {ResponseReader} => R }: R / Exception[RequestError] = internal::backend() match {
335
+ // TODO use a proper dispatch after #448 is resolved
335
336
case "js-node" => jsNode::request{body}{res}
336
337
case "js-web" => jsWeb::request{body}{res}
337
338
case _ => <>
338
339
}
339
340
341
+ // Simple API
342
+ // ----------
343
+ interface HttpClient {
344
+ def get[R](url: String, body: Option[String], headers: List[(String, String)]){ r: {ResponseReader} => R }: R / Exception[RequestError]
345
+ def post[R](url: String, body: Option[String], headers: List[(String, String)]){ r: {ResponseReader} => R }: R / Exception[RequestError]
346
+ }
347
+
348
+ def httpClient[R]{ body: => R / HttpClient }: R = {
349
+ try body() with HttpClient {
350
+ def get[R](url, body, headers) = resume { {k} =>
351
+ with on[WrongFormat].default{ do raise(RequestError(), "Malformed URL") }
352
+ request{
353
+ do method(GET())
354
+ uri(url)
355
+ defaultHeaders()
356
+ body.foreach { data =>
357
+ do body{
358
+ with encodeUTF8
359
+ data.each
360
+ }
361
+ }
362
+ headers.foreach { case (k, v) =>
363
+ do header(k, v)
364
+ }
365
+ }{k}
366
+ }
367
+ def post[R](url, body, headers) = resume { {k} =>
368
+ with on[WrongFormat].default{ do raise(RequestError(), "Malformed URL") }
369
+ request{
370
+ do method(POST())
371
+ uri(url)
372
+ defaultHeaders()
373
+ body.foreach { data =>
374
+ do body{
375
+ with encodeUTF8
376
+ data.each
377
+ }
378
+ }
379
+ headers.foreach { case (k, v) =>
380
+ do header(k, v)
381
+ }
382
+ }{k}
383
+ }
384
+ }
385
+ }
386
+
387
+ /// GET the given URL with the given body and headers, emitting the response characters.
388
+ /// Raises an exception if anything goes wrong, including non-200 responses.
389
+ def getStreaming(url: String, body: Option[String], headers: List[(String, String)]): Unit / { emit[Char], Exception[RequestError], HttpClient } =
390
+ do get(url, body, headers){ {r} =>
391
+ if(r.status() != 200) { do raise(RequestError(), "Non-200 response") }
392
+ with source[Byte]{ r.body() }
393
+ with decodeUTF8
394
+ exhaustively{ do emit(do read[Char]()) }
395
+ }
396
+ /// GET the given URL with the given body and headers, returning the response body.
397
+ /// Raises an exception if anything goes wrong, including non-200 responses.
398
+ def get(url: String, body: Option[String], headers: List[(String, String)]): String / { Exception[RequestError], HttpClient } =
399
+ collectString{ getStreaming(url, body, headers) }
400
+ /// GET the given URL, returning the response body.
401
+ /// Raises an exception if anything goes wrong, including non-200 responses.
402
+ def get(url: String): String / { Exception[RequestError], HttpClient } = get(url, None(), Nil())
403
+ /// GET the given URL, emitting the response characters.
404
+ /// Raises an exception if anything goes wrong, including non-200 responses.
405
+ def getStreaming(url: String): Unit / { emit[Char], Exception[RequestError], HttpClient } = getStreaming(url, None(), Nil())
406
+
407
+ /// POST to the given URL with the given body and headers, emitting the response characters.
408
+ /// Raises an exception if anything goes wrong, including non-200 responses.
409
+ def postStreaming(url: String, body: Option[String], headers: List[(String, String)]): Unit / { emit[Char], Exception[RequestError], HttpClient } =
410
+ do post(url, body, headers){ {r} =>
411
+ if(r.status() != 200) { do raise(RequestError(), "Non-200 response") }
412
+ with source[Byte]{ r.body() }
413
+ with decodeUTF8
414
+ exhaustively{ do emit(do read[Char]()) }
415
+ }
416
+ /// POST to the given URL with the given body and headers, returning the response body.
417
+ /// Raises an exception if anything goes wrong, including non-200 responses.
418
+ def post(url: String, body: Option[String], headers: List[(String, String)]): String / { Exception[RequestError], HttpClient } =
419
+ collectString{ postStreaming(url, body, headers) }
420
+ /// POST to the given URL, returning the response body.
421
+ /// Raises an exception if anything goes wrong, including non-200 responses.
422
+ def post(url: String): String / { Exception[RequestError], HttpClient } = post(url, None(), Nil())
423
+ /// POST to the given URL, emitting the response characters.
424
+ /// Raises an exception if anything goes wrong, including non-200 responses.
425
+ def post(url: String): Unit / { emit[Char], Exception[RequestError], HttpClient } = postStreaming(url, None(), Nil())
426
+
340
427
namespace example {
341
- def main() = {
428
+
429
+ def lowLevelApi() = {
342
430
with on[RequestError].panic
343
431
with on[WrongFormat].panic
344
432
with def res = request{
@@ -364,4 +452,15 @@ namespace example {
364
452
println(res.status().show)
365
453
}
366
454
}
455
+ def simpleApi() = {
456
+ with on[RequestError].panic
457
+ with httpClient
458
+ println(get("https://effekt-lang.org"))
459
+ }
460
+ def main() = {
461
+ println("Low-level: ")
462
+ lowLevelApi()
463
+ println("Simple: ")
464
+ simpleApi()
465
+ }
367
466
}
0 commit comments