-
Notifications
You must be signed in to change notification settings - Fork 231
/
Copy pathGraphResponseHandler.ts
182 lines (172 loc) · 5.84 KB
/
GraphResponseHandler.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
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/
/**
* @module GraphResponseHandler
* References - https://fetch.spec.whatwg.org/#responses
*/
import { GraphRequestCallback } from "./IGraphRequestCallback";
import { ResponseType } from "./ResponseType";
/**
* @enum
* Enum for document types
* @property {string} TEXT_HTML - The text/html content type
* @property {string} TEXT_XML - The text/xml content type
* @property {string} APPLICATION_XML - The application/xml content type
* @property {string} APPLICATION_XHTML - The application/xhml+xml content type
*/
export enum DocumentType {
TEXT_HTML = "text/html",
TEXT_XML = "text/xml",
APPLICATION_XML = "application/xml",
APPLICATION_XHTML = "application/xhtml+xml",
}
/**
* @enum
* Enum for Content types
* @property {string} TEXT_PLAIN - The text/plain content type
* @property {string} APPLICATION_JSON - The application/json content type
*/
enum ContentType {
TEXT_PLAIN = "text/plain",
APPLICATION_JSON = "application/json",
}
/**
* @enum
* Enum for Content type regex
* @property {string} DOCUMENT - The regex to match document content types
* @property {string} IMAGE - The regex to match image content types
*/
enum ContentTypeRegexStr {
DOCUMENT = "^(text\\/(html|xml))|(application\\/(xml|xhtml\\+xml))$",
IMAGE = "^image\\/.+",
}
/**
* @class
* Class for GraphResponseHandler
*/
export class GraphResponseHandler {
/**
* @private
* @static
* To parse Document response
* @param {Response} rawResponse - The response object
* @param {DocumentType} type - The type to which the document needs to be parsed
* @returns A promise that resolves to a document content
*/
private static parseDocumentResponse(rawResponse: Response, type: DocumentType): Promise<any> {
if (typeof DOMParser !== "undefined") {
return new Promise((resolve, reject) => {
rawResponse.text().then((xmlString) => {
try {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, type);
resolve(xmlDoc);
} catch (error) {
reject(error);
}
});
});
} else {
return Promise.resolve(rawResponse.body);
}
}
/**
* @private
* @static
* @async
* To convert the native Response to response content
* @param {Response} rawResponse - The response object
* @param {ResponseType} [responseType] - The response type value
* @returns A promise that resolves to the converted response content
*/
private static async convertResponse(rawResponse: Response, responseType?: ResponseType): Promise<any> {
if (rawResponse.status === 204) {
// NO CONTENT
return Promise.resolve();
}
let responseValue: any;
const contentType = rawResponse.headers.get("Content-type");
switch (responseType) {
case ResponseType.ARRAYBUFFER:
responseValue = await rawResponse.arrayBuffer();
break;
case ResponseType.BLOB:
responseValue = await rawResponse.blob();
break;
case ResponseType.DOCUMENT:
responseValue = await GraphResponseHandler.parseDocumentResponse(rawResponse, DocumentType.TEXT_XML);
break;
case ResponseType.JSON:
responseValue = await rawResponse.json();
break;
case ResponseType.STREAM:
responseValue = await Promise.resolve(rawResponse.body);
break;
case ResponseType.TEXT:
responseValue = await rawResponse.text();
break;
default:
if (contentType !== null) {
const mimeType = contentType.split(";")[0];
if (new RegExp(ContentTypeRegexStr.DOCUMENT).test(mimeType)) {
responseValue = await GraphResponseHandler.parseDocumentResponse(rawResponse, mimeType as DocumentType);
} else if (new RegExp(ContentTypeRegexStr.IMAGE).test(mimeType)) {
responseValue = rawResponse.blob();
} else if (mimeType === ContentType.TEXT_PLAIN) {
responseValue = await rawResponse.text();
} else if (mimeType === ContentType.APPLICATION_JSON) {
responseValue = await rawResponse.json();
} else {
responseValue = Promise.resolve(rawResponse.body);
}
} else {
/**
* RFC specification {@link https://tools.ietf.org/html/rfc7231#section-3.1.1.5} says:
* A sender that generates a message containing a payload body SHOULD
* generate a Content-Type header field in that message unless the
* intended media type of the enclosed representation is unknown to the
* sender. If a Content-Type header field is not present, the recipient
* MAY either assume a media type of "application/octet-stream"
* ([RFC2046], Section 4.5.1) or examine the data to determine its type.
*
* So assuming it as a stream type so returning the body.
*/
responseValue = Promise.resolve(rawResponse.body);
}
break;
}
return responseValue;
}
/**
* @public
* @static
* @async
* To get the parsed response
* @param {Response} rawResponse - The response object
* @param {ResponseType} [responseType] - The response type value
* @param {GraphRequestCallback} [callback] - The graph request callback function
* @returns The parsed response
*/
public static async getResponse(rawResponse: Response, responseType?: ResponseType, callback?: GraphRequestCallback): Promise<any> {
if (responseType === ResponseType.RAW) {
return Promise.resolve(rawResponse);
} else {
const response = await GraphResponseHandler.convertResponse(rawResponse, responseType);
if (rawResponse.ok) {
// Status Code 2XX
if (typeof callback === "function") {
callback(null, response);
} else {
return response;
}
} else {
// NOT OK Response
throw response;
}
}
}
}