-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathfetch.js.mbt
More file actions
79 lines (72 loc) · 2.22 KB
/
fetch.js.mbt
File metadata and controls
79 lines (72 loc) · 2.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
///|
extern "js" fn fetch_ffi(url : String, options : @js.Value) -> @js.Promise =
#| (url, options) => fetch(url, options)
///|
extern "js" fn fetch_response_status(resp : @js.Value) -> Int =
#| (resp) => resp.status
///|
extern "js" fn fetch_response_bytes(resp : @js.Value) -> @js.Promise =
#| async (resp) => {
#| const ab = await resp.arrayBuffer();
#| return Array.from(new Uint8Array(ab));
#| }
///|
extern "js" fn fetch_response_headers_json(resp : @js.Value) -> String =
#| (resp) => {
#| const out = {};
#| resp.headers.forEach((value, key) => {
#| out[key] = value;
#| });
#| return JSON.stringify(out);
#| }
///|
fn parse_headers_json(
json_str : String,
) -> Map[StringView, StringView] raise Error {
let headers : Map[StringView, StringView] = {}
match @json.parse(json_str) {
Object(obj) => {
obj.each(fn(k, v) { if v is String(s) { headers.set(k, s) } })
headers
}
_ =>
raise FetchError::RequestFailed("response headers is not a JSON object")
}
}
///|
pub async fn fetch(
url : String,
body? : String,
http_method : HttpMethod,
data? : &Responder,
headers? : Map[String, String],
credentials? : FetchCredentials,
mode? : FetchMode,
) -> HttpResponse raise Error {
let (req_body, req_headers) = prepare_fetch_payload(body, data, headers)
let options = @js.Object::new()
options["method"] = http_method.to_string()
if req_body is Some(body_str) {
options["body"] = body_str
}
if !req_headers.is_empty() {
let headers_obj = @js.Object::new()
req_headers.each(fn(k, v) { headers_obj[k] = v })
options["headers"] = headers_obj.to_value()
}
ignore(credentials)
ignore(mode)
let resp = fetch_ffi(url, options.to_value()).wait() catch {
e => raise FetchError::RequestFailed("js fetch failed: \{e}")
}
let status = fetch_response_status(resp)
let body_arr : Array[Byte] = fetch_response_bytes(resp).wait().cast() catch {
e => raise FetchError::RequestFailed("read response body failed: \{e}")
}
let response_headers = parse_headers_json(fetch_response_headers_json(resp))
HttpResponse::new(
StatusCode::from_int(status),
headers=response_headers,
raw_body=Bytes::from_array(body_arr),
)
}