UNPKG

5.98 kBPlain TextView Raw
1/**
2 * -------------------------------------------------------------------------------------------
3 * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4 * See License in the project root for license information.
5 * -------------------------------------------------------------------------------------------
6 */
7
8/**
9 * @module GraphResponseHandler
10 * References - https://fetch.spec.whatwg.org/#responses
11 */
12
13import { GraphRequestCallback } from "./IGraphRequestCallback";
14import { ResponseType } from "./ResponseType";
15
16/**
17 * @enum
18 * Enum for document types
19 * @property {string} TEXT_HTML - The text/html content type
20 * @property {string} TEXT_XML - The text/xml content type
21 * @property {string} APPLICATION_XML - The application/xml content type
22 * @property {string} APPLICATION_XHTML - The application/xhml+xml content type
23 */
24export enum DocumentType {
25 TEXT_HTML = "text/html",
26 TEXT_XML = "text/xml",
27 APPLICATION_XML = "application/xml",
28 APPLICATION_XHTML = "application/xhtml+xml",
29}
30
31/**
32 * @enum
33 * Enum for Content types
34 * @property {string} TEXT_PLAIN - The text/plain content type
35 * @property {string} APPLICATION_JSON - The application/json content type
36 */
37
38enum ContentType {
39 TEXT_PLAIN = "text/plain",
40 APPLICATION_JSON = "application/json",
41}
42
43/**
44 * @enum
45 * Enum for Content type regex
46 * @property {string} DOCUMENT - The regex to match document content types
47 * @property {string} IMAGE - The regex to match image content types
48 */
49enum ContentTypeRegexStr {
50 DOCUMENT = "^(text\\/(html|xml))|(application\\/(xml|xhtml\\+xml))$",
51 IMAGE = "^image\\/.+",
52}
53
54/**
55 * @class
56 * Class for GraphResponseHandler
57 */
58
59export class GraphResponseHandler {
60 /**
61 * @private
62 * @static
63 * To parse Document response
64 * @param {Response} rawResponse - The response object
65 * @param {DocumentType} type - The type to which the document needs to be parsed
66 * @returns A promise that resolves to a document content
67 */
68 private static parseDocumentResponse(rawResponse: Response, type: DocumentType): Promise<any> {
69 if (typeof DOMParser !== "undefined") {
70 return new Promise((resolve, reject) => {
71 rawResponse.text().then((xmlString) => {
72 try {
73 const parser = new DOMParser();
74 const xmlDoc = parser.parseFromString(xmlString, type);
75 resolve(xmlDoc);
76 } catch (error) {
77 reject(error);
78 }
79 });
80 });
81 } else {
82 return Promise.resolve(rawResponse.body);
83 }
84 }
85
86 /**
87 * @private
88 * @static
89 * @async
90 * To convert the native Response to response content
91 * @param {Response} rawResponse - The response object
92 * @param {ResponseType} [responseType] - The response type value
93 * @returns A promise that resolves to the converted response content
94 */
95 private static async convertResponse(rawResponse: Response, responseType?: ResponseType): Promise<any> {
96 if (rawResponse.status === 204) {
97 // NO CONTENT
98 return Promise.resolve();
99 }
100 let responseValue: any;
101 const contentType = rawResponse.headers.get("Content-type");
102 switch (responseType) {
103 case ResponseType.ARRAYBUFFER:
104 responseValue = await rawResponse.arrayBuffer();
105 break;
106 case ResponseType.BLOB:
107 responseValue = await rawResponse.blob();
108 break;
109 case ResponseType.DOCUMENT:
110 responseValue = await GraphResponseHandler.parseDocumentResponse(rawResponse, DocumentType.TEXT_XML);
111 break;
112 case ResponseType.JSON:
113 responseValue = await rawResponse.json();
114 break;
115 case ResponseType.STREAM:
116 responseValue = await Promise.resolve(rawResponse.body);
117 break;
118 case ResponseType.TEXT:
119 responseValue = await rawResponse.text();
120 break;
121 default:
122 if (contentType !== null) {
123 const mimeType = contentType.split(";")[0];
124 if (new RegExp(ContentTypeRegexStr.DOCUMENT).test(mimeType)) {
125 responseValue = await GraphResponseHandler.parseDocumentResponse(rawResponse, mimeType as DocumentType);
126 } else if (new RegExp(ContentTypeRegexStr.IMAGE).test(mimeType)) {
127 responseValue = rawResponse.blob();
128 } else if (mimeType === ContentType.TEXT_PLAIN) {
129 responseValue = await rawResponse.text();
130 } else if (mimeType === ContentType.APPLICATION_JSON) {
131 responseValue = await rawResponse.json();
132 } else {
133 responseValue = Promise.resolve(rawResponse.body);
134 }
135 } else {
136 /**
137 * RFC specification {@link https://tools.ietf.org/html/rfc7231#section-3.1.1.5} says:
138 * A sender that generates a message containing a payload body SHOULD
139 * generate a Content-Type header field in that message unless the
140 * intended media type of the enclosed representation is unknown to the
141 * sender. If a Content-Type header field is not present, the recipient
142 * MAY either assume a media type of "application/octet-stream"
143 * ([RFC2046], Section 4.5.1) or examine the data to determine its type.
144 *
145 * So assuming it as a stream type so returning the body.
146 */
147 responseValue = Promise.resolve(rawResponse.body);
148 }
149 break;
150 }
151 return responseValue;
152 }
153
154 /**
155 * @public
156 * @static
157 * @async
158 * To get the parsed response
159 * @param {Response} rawResponse - The response object
160 * @param {ResponseType} [responseType] - The response type value
161 * @param {GraphRequestCallback} [callback] - The graph request callback function
162 * @returns The parsed response
163 */
164 public static async getResponse(rawResponse: Response, responseType?: ResponseType, callback?: GraphRequestCallback): Promise<any> {
165 if (responseType === ResponseType.RAW) {
166 return Promise.resolve(rawResponse);
167 } else {
168 const response = await GraphResponseHandler.convertResponse(rawResponse, responseType);
169 if (rawResponse.ok) {
170 // Status Code 2XX
171 if (typeof callback === "function") {
172 callback(null, response);
173 } else {
174 return response;
175 }
176 } else {
177 // NOT OK Response
178 throw response;
179 }
180 }
181 }
182}