forked from syncfusion/ej2-javascript-ui-controls
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfetch.ts
184 lines (179 loc) · 6.5 KB
/
fetch.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import { isNullOrUndefined as isNOU, isObject, merge } from './util';
/**
* The Fetch class provides a way to make asynchronous network requests, typically to retrieve resources from a server.
* ```typescript
* var fetchApi = new Fetch('index.html', 'GET');
* fetchApi.send()
* .then((value) => {
* console.log(value);
* }).catch((error) => {
* console.log(error);
* });
* ```
*/
export class Fetch {
/**
* Specifies the URL to which the request is to be sent.
*
* @default null
*/
public url: string;
/**
* Specifies which request method is to be used, such as GET, POST, etc.
*
* @default GET
*/
public type: string = 'GET';
/**
* Specifies the content type of the request, which is used to indicate the original media type of the resource.
*
* @default null
*/
public contentType: string;
/**
* Specifies the data that needs to be added to the request.
*
* @default null
*/
public data: string | Object;
/**
* A boolean value indicating whether to reject the promise or not.
*
* @private
* @default true
*/
public emitError: boolean = true;
/**
* Specifies the request object that represents a resource request.
*
* @default null
*/
public fetchRequest: Request;
/**
* Represents a response to a request.
*
* @private
* @default null
*/
private fetchResponse: Promise<Response>;
/**
* Specifies the callback function to be triggered before sending the request to the server.
* This can be used to modify the fetchRequest object before it is sent.
*
* @event beforeSend
*/
public beforeSend: Function;
/**
* Specifies the callback function to be triggered after the response is received.
* This callback will be triggered even if the request is failed.
*
* @event onLoad
*/
public onLoad: Function;
/**
* Specifies the callback function to be triggered after the request is successful.
* The callback will contain the server response as a parameter.
*
* @event onSuccess
*/
public onSuccess: Function;
/**
* Specifies the callback function to be triggered after the request is failed.
*
* @event onFailure
*/
public onFailure: Function;
/**
* Constructor for Fetch class.
*
* @param {string|Object} options - Specifies the URL or Request object with URL to which the request is to be sent.
* @param {string} type - Specifies which request method is to be used, such as GET, POST, etc.
* @param {string} contentType - Specifies the content type of the request, which is used to indicate the original media type of the resource.
*/
constructor(options?: string | Object, type?: string, contentType?: string) {
if (typeof options === 'string') {
this.url = options;
this.type = !isNOU(type) ? type.toUpperCase() : this.type;
this.contentType = contentType;
}
else if (isObject(options) && Object.keys(options).length > 0) {
merge(this, options);
}
this.contentType = !isNOU(this.contentType) ? this.contentType : 'application/json; charset=utf-8';
}
/**
* Send the request to server.
*
* @param {string|Object} data - Specifies the data that needs to be added to the request.
* @returns {Promise<Response>} - Returns the response to a request.
*/
public send(data?: string | Object): Promise<Response> {
const contentTypes: Object = {
'application/json': 'json',
'multipart/form-data': 'formData',
'application/octet-stream': 'blob',
'application/x-www-form-urlencoded': 'formData'
};
try {
if (isNOU(this.fetchRequest) && this.type === 'GET') {
this.fetchRequest = new Request(this.url, { method: this.type });
} else if (isNOU(this.fetchRequest)) {
this.data = !isNOU(data) ? data : this.data;
this.fetchRequest = new Request(this.url, {
method: this.type,
headers: { 'Content-Type': this.contentType },
body: this.data as BodyInit
});
}
const eventArgs: BeforeSendFetchEventArgs = { cancel: false, fetchRequest: this.fetchRequest };
this.triggerEvent(this['beforeSend'], eventArgs);
if (eventArgs.cancel) { return null; }
this.fetchResponse = fetch(this.fetchRequest);
return this.fetchResponse.then((response: Response) => {
this.triggerEvent(this['onLoad'], response);
if (!response.ok) {
throw new Error(response.statusText);
}
let responseType: string = 'text';
for (const key of Object.keys(contentTypes)) {
if ((response.headers.get('Content-Type') as string).indexOf(key) !== -1) {
responseType = contentTypes[key as string];
}
}
return response[responseType as string]();
// eslint-disable-next-line
}).then((data: any) => {
this.triggerEvent(this['onSuccess'], data, this);
return data;
// eslint-disable-next-line
}).catch((error: any) => {
let returnVal: Object = {};
if (this.emitError) {
this.triggerEvent(this['onFailure'], error);
returnVal = Promise.reject(error);
}
return returnVal;
});
} catch (error) {
return error;
}
}
private triggerEvent(callback: Function, data?: string | Object, instance?: Fetch): void {
if (!isNOU(callback) && typeof callback === 'function') {
callback(data, instance);
}
}
}
/**
* Provides information about the beforeSend event.
*/
export interface BeforeSendFetchEventArgs {
/**
* A boolean value indicating whether to cancel the fetch request or not.
*/
cancel?: boolean;
/**
* Returns the request object that represents a resource request.
*/
fetchRequest: Request;
}