forked from gleam-lang/fetch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgleam_fetch_ffi.mjs
167 lines (145 loc) · 4.45 KB
/
gleam_fetch_ffi.mjs
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import { Ok, Error, List, toBitArray, toList } from "./gleam.mjs";
import { to_string as uri_to_string } from "../gleam_stdlib/gleam/uri.mjs";
import { method_to_string } from "../gleam_http/gleam/http.mjs";
import { to_uri } from "../gleam_http/gleam/http/request.mjs";
import { Response } from "../gleam_http/gleam/http/response.mjs";
import {
NetworkError,
InvalidJsonBody,
UnableToReadBody,
} from "../gleam_fetch/gleam/fetch.mjs";
export async function raw_send(request) {
try {
return new Ok(await fetch(request));
} catch (error) {
return new Error(new NetworkError(error.toString()));
}
}
export function from_fetch_response(response) {
return new Response(
response.status,
List.fromArray([...response.headers]),
response
);
}
function request_common(request) {
let url = uri_to_string(to_uri(request));
let method = method_to_string(request.method).toUpperCase();
let options = {
headers: make_headers(request.headers),
method,
};
return [url, options]
}
export function to_fetch_request(request) {
let [url, options] = request_common(request)
if (options.method !== "GET" && options.method !== "HEAD") options.body = request.body;
return new globalThis.Request(url, options);
}
export function form_data_to_fetch_request(request) {
let [url, options] = request_common(request)
if (options.method !== "GET" && options.method !== "HEAD") options.body = request.body;
// Remove `content-type`, because the browser will add the correct header by itself.
delete options.headers['content-type']
return new globalThis.Request(url, options);
}
export function bitarray_request_to_fetch_request(request) {
let [url, options] = request_common(request)
if (options.method !== "GET" && options.method !== "HEAD") options.body = request.body.rawBuffer;
return new globalThis.Request(url, options);
}
function make_headers(headersList) {
let headers = new globalThis.Headers();
for (let [k, v] of headersList) headers.append(k.toLowerCase(), v);
return headers;
}
export async function read_bytes_body(response) {
let body;
try {
body = await response.body.arrayBuffer()
} catch (error) {
return new Error(new UnableToReadBody());
}
return new Ok(response.withFields({ body: toBitArray(new Uint8Array(body)) }));
}
export async function read_text_body(response) {
let body;
try {
body = await response.body.text();
} catch (error) {
return new Error(new UnableToReadBody());
}
return new Ok(response.withFields({ body }));
}
export async function read_json_body(response) {
try {
let body = await response.body.json();
return new Ok(response.withFields({ body }));
} catch (error) {
return new Error(new InvalidJsonBody());
}
}
// FormData functions.
export function newFormData() {
return new FormData()
}
function cloneFormData(formData) {
const f = new FormData()
for (const [key, value] of formData.entries()) f.append(key, value)
return f
}
export function appendFormData(formData, key, value) {
const f = cloneFormData(formData)
f.append(key, value)
return f
}
export function setFormData(formData, key, value) {
const f = cloneFormData(formData)
f.set(key, value)
return f
}
export function appendBitsFormData(formData, key, value) {
const f = cloneFormData(formData)
f.append(key, new Blob([value.rawBuffer]))
return f
}
export function setBitsFormData(formData, key, value) {
const f = cloneFormData(formData)
f.set(key, new Blob([value.rawBuffer]))
return f
}
export function deleteFormData(formData, key) {
const f = cloneFormData(formData)
f.delete(key)
return f
}
export function getFormData(formData, key) {
const data = [...formData.getAll(key)]
return toList(data.filter(value => typeof value === 'string'))
}
export async function getBitsFormData(formData, key) {
const data = [...formData.getAll(key)]
const encode = new TextEncoder()
const blobs = data.map(async (value) => {
if (typeof value === 'string') {
const encoded = encode.encode(value)
return toBitArray(encoded)
} else {
const buffer = await value.arrayBuffer()
const bytes = new Uint8Array(buffer)
return toBitArray(bytes)
}
})
const bytes = await Promise.all(blobs)
return toList(bytes)
}
export function hasFormData(formData, key) {
return formData.has(key)
}
export function keysFormData(formData) {
const result = new Set()
for (const key of formData.keys()) {
result.add(key)
}
return toList([...result])
}