Skip to content

Commit deff22e

Browse files
Add simple API variant
1 parent fb33d79 commit deff22e

File tree

1 file changed

+100
-1
lines changed

1 file changed

+100
-1
lines changed

libraries/common/io/requests.effekt

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,13 +332,101 @@ namespace internal {
332332
/// The Request body is buffered, the response is streaming (as far
333333
/// as the backend implementation allows).
334334
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
335336
case "js-node" => jsNode::request{body}{res}
336337
case "js-web" => jsWeb::request{body}{res}
337338
case _ => <>
338339
}
339340

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+
340427
namespace example {
341-
def main() = {
428+
429+
def lowLevelApi() = {
342430
with on[RequestError].panic
343431
with on[WrongFormat].panic
344432
with def res = request{
@@ -364,4 +452,15 @@ namespace example {
364452
println(res.status().show)
365453
}
366454
}
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+
}
367466
}

0 commit comments

Comments
 (0)