-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttputil.ts
More file actions
110 lines (84 loc) · 2.95 KB
/
httputil.ts
File metadata and controls
110 lines (84 loc) · 2.95 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
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
import { asError } from 'f61ui/errors';
import { StructuredErrorResponse } from 'f61ui/types';
export async function getJson<T>(url: string): Promise<T> {
const headers: { [key: string]: string } = {
Accept: 'application/json',
};
const csrfToken = readCsrfToken();
if (csrfToken) {
headers['x-csrf-token'] = csrfToken;
}
const response = await fetch(url, { method: 'GET', headers });
await httpMustBeOk(response);
return await response.json();
}
export async function postJson<I, O>(url: string, body: I): Promise<O> {
const response = await postJsonReturningVoid<I>(url, body);
return await response.json();
}
export async function postJsonReturningVoid<T>(url: string, body: T): Promise<Response> {
const bodyToPost = JSON.stringify(body);
const headers: { [key: string]: string } = {
Accept: 'application/json',
'Content-Type': 'application/json',
};
const csrfToken = readCsrfToken();
if (csrfToken) {
headers['x-csrf-token'] = csrfToken;
}
const response = await fetch(url, {
headers,
method: 'POST',
body: bodyToPost,
});
await httpMustBeOk(response);
return response;
}
export async function httpMustBeOk(response: Response): Promise<void> {
if (response.ok) {
return;
}
// response not ok, dig up response body to make a detailed error object
let responseBody: string;
try {
responseBody = await response.text();
} catch (err) {
throw new Error(
'HTTP response failure. Also, error fetching response body: ' + asError(err).toString(),
);
}
if (response.headers.get('content-type') === 'application/json') {
throw JSON.parse(responseBody) as StructuredErrorResponse;
} else {
throw new Error('HTTP response failure: ' + responseBody);
}
}
export function makeQueryParams(path: string, params: QueryParams): string {
const queryParamKvs = Object.keys(params).map(
(key) => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]),
);
return queryParamKvs.length === 0 ? path : path + '?' + queryParamKvs.join('&');
}
export interface QueryParams {
[key: string]: string;
}
export function parseQueryParams(queryParamsSerialized: string): QueryParams {
// "foo=bar&quu=qux" => ["foo=bar", "quu=qux"]
const queryParPairs = queryParamsSerialized === '' ? [] : queryParamsSerialized.split('&');
return queryParPairs.reduce((acc, current) => {
const eqPos = current.indexOf('=');
const key = decodeQueryParam(current.substr(0, eqPos));
const value = decodeQueryParam(current.substr(eqPos + 1));
acc[key] = value;
return acc;
}, {} as QueryParams);
}
function decodeQueryParam(p: string): string {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#decoding_query_parameters_from_a_url
return decodeURIComponent(p.replace(/\+/g, ' '));
}
function readCsrfToken(): string | null {
// TODO: fix this botched way of reading the cookie value..
const csrfToken = /csrf_token=([^;]+)/.exec(document.cookie);
return csrfToken ? csrfToken[1] : null;
}