roc/examples/cli/cli-platform/Http.roc
2022-11-24 03:21:14 -05:00

111 lines
3.2 KiB
Text

interface Http
exposes [
Request,
Method,
Header,
TimeoutConfig,
Body,
Response,
Metadata,
Error,
header,
emptyBody,
bytesBody,
stringBody,
handleStringResponse,
defaultRequest,
errorToString,
send,
]
imports [Effect, InternalTask, Task.{ Task }, InternalHttp]
Request : InternalHttp.Request
Method : InternalHttp.Method
Header : InternalHttp.Header
TimeoutConfig : InternalHttp.TimeoutConfig
Body : InternalHttp.Body
Response : InternalHttp.Response
Metadata : InternalHttp.Metadata
Error : InternalHttp.Error
defaultRequest : Request
defaultRequest = {
method: Get,
headers: [],
url: "",
body: Http.emptyBody,
timeout: NoTimeout,
}
## An HTTP header for configuring requests. See a bunch of common headers
## [here](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields).
##
header : Str, Str -> Header
header =
Header
emptyBody : Body
emptyBody =
EmptyBody
bytesBody : [MimeType Str], List U8 -> Body
bytesBody =
Body
stringBody : [MimeType Str], Str -> Body
stringBody = \mimeType, str ->
Body mimeType (Str.toUtf8 str)
# jsonBody : a -> Body | a has Encoding
# jsonBody = \val ->
# Body (MimeType "application/json") (Encode.toBytes val Json.format)
#
# multiPartBody : List Part -> Body
# multiPartBody = \parts ->
# boundary = "7MA4YWxkTrZu0gW" # TODO: what's this exactly? a hash of all the part bodies?
# beforeName = Str.toUtf8 "-- \(boundary)\r\nContent-Disposition: form-data; name=\""
# afterName = Str.toUtf8 "\"\r\n"
# appendPart = \buffer, Part name partBytes ->
# buffer
# |> List.concat beforeName
# |> List.concat (Str.toUtf8 name)
# |> List.concat afterName
# |> List.concat partBytes
# bodyBytes = List.walk parts [] appendPart
# Body (MimeType "multipart/form-data;boundary=\"\(boundary)\"") bodyBytes
# bytesPart : Str, List U8 -> Part
# bytesPart =
# Part
# stringPart : Str, Str -> Part
# stringPart = \name, str ->
# Part name (Str.toUtf8 str)
handleStringResponse : Response -> Result Str Error
handleStringResponse = \response ->
when response is
BadRequest err -> Err (BadRequest err)
Timeout -> Err Timeout
NetworkError -> Err NetworkError
BadStatus metadata _ -> Err (BadStatus metadata.statusCode)
GoodStatus _ bodyBytes ->
Str.fromUtf8 bodyBytes
|> Result.mapErr
\BadUtf8 _ pos ->
position = Num.toStr pos
BadBody "Invalid UTF-8 at byte offset \(position)"
errorToString : Error -> Str
errorToString = \err ->
when err is
BadRequest e -> "Invalid Request: \(e)"
Timeout -> "Request timed out"
NetworkError -> "Network error"
BadStatus code -> Str.concat "Request failed with status " (Num.toStr code)
BadBody details -> Str.concat "Request failed. Invalid body. " details
send : Request -> Task Str Error
send = \req ->
# TODO: Fix our C ABI codegen so that we don't this Box.box heap allocation
Effect.sendRequest (Box.box req)
|> Effect.map handleStringResponse
|> InternalTask.fromEffect