-
Notifications
You must be signed in to change notification settings - Fork 108
/
Request.ts
159 lines (145 loc) · 4.39 KB
/
Request.ts
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
/**
* Manages the requests to send. Chain methods to update options.
* Must call .get/.post/.patch/.remove to send the request with given options.
*/
class Request {
url: string;
authToken: string;
queryString: string;
options: RequestOptions;
nextPageToken?: string | null;
documents?: any[];
fields?: Record<string, any>;
/**
* @param url the base url to utilize
* @param authToken authorization token to make requests
* @param options [Optional] set of options to utilize over the default headers
*/
constructor(url: string, authToken?: string, options?: RequestOptions) {
this.url = url;
this.queryString = '';
this.authToken = authToken || '';
if (!this.authToken) options = options || {};
// Set default header options if none are passed in
this.options = options || {
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer ' + this.authToken,
},
};
this.options['muteHttpExceptions'] = true;
}
/**
* Sets the payload option
*
* @param obj Object payload to stringify
* @return {Request} this request to be chained
*/
payload(obj: Record<string, any>): Request {
this.options['payload'] = JSON.stringify(obj);
return this;
}
/**
* Sets the type of REST method to send
*
* @param type String value equal to one of the REST method types
* @param path the path to send the request to
* @return {any} this request to be chained
*/
method_<T>(type: Method, path?: string): T {
const url = this.url + Util_.cleanPath(path || '') + this.queryString;
this.options['method'] = type;
const response: GoogleAppsScript.URL_Fetch.HTTPResponse = UrlFetchApp.fetch(url, this.options);
const responseObj: T = JSON.parse(response.getContentText());
this.checkForError(responseObj);
return responseObj;
}
/**
* Adds a parameter to the URL query string.
* Can be repeated for additional key-value mappings
*
* @param {string} key the key to add
* @param {string} value the value to set
* @return {this} this request to be chained
*/
addParam(key: string, value: string): this {
this.queryString += (this.queryString.startsWith('?') ? '&' : '?') + Util_.parameterize({ [key]: value });
return this;
}
/**
* Alters the route by prepending the query string.
*
* @param {string} route to set
* @return {this} this request to be chained
*/
route(route: string): this {
this.queryString = `:${route}${this.queryString}`;
return this;
}
/**
* Set request as a GET method
*
* @param {string} path the path to send the request to
* @return {T} JSON Object response
*/
get<T>(path: string): T {
return this.method_<T>('get', path);
}
/**
* Set request as a POST method
*
* @param path the path to send the request to
* @param obj [Optional] object to send as payload
* @return {Request} this request to be chained
*/
post<T>(path?: string, obj?: Record<string, any>): T {
if (obj) {
this.payload(obj);
}
return this.method_<T>('post', path);
}
/**
* Set request as a PATCH method.
*
* @param path the path to send the request to
* @param obj Optional object to send as payload
* @return {Request} this request to be chained
*/
patch<T>(path?: string, obj?: Record<string, any>): T {
if (obj) {
this.payload(obj);
}
return this.method_<T>('patch', path);
}
/**
* Set request as a DELETE method (delete is a keyword)
*
* @param path the path to send the request to
* @return {Request} this request to be chained
*/
remove<T>(path: string): T {
return this.method_<T>('delete', path);
}
/**
* Used to clone the request instance. Useful for firing multiple requests.
*
* @return {Request} A copy of this object
*/
clone(): Request {
return new Request(this.url, this.authToken, this.options);
}
/**
* Validate response object for errors
*
* @param {any} responseObj HTTP response object to validate
* @throws Error if HTTP request errors found
*/
checkForError(responseObj: any): void {
if (responseObj.error) {
throw new Error(responseObj.error.message || responseObj.error.error_description || responseObj.error);
}
if (Array.isArray(responseObj) && responseObj.length && responseObj[0].error) {
throw new Error(responseObj[0].error.message);
}
}
}