import { AjaxRequest, AjaxResponseType } from './types'; import { getXHRResponse } from './getXHRResponse'; /** * A normalized response from an AJAX request. To get the data from the response, * you will want to read the `response` property. * * - DO NOT create instances of this class directly. * - DO NOT subclass this class. * * It is advised not to hold this object in memory, as it has a reference to * the original XHR used to make the request, as well as properties containing * request and response data. * * @see {@link ajax} * @see {@link AjaxConfig} */ export class AjaxResponse { /** The HTTP status code */ readonly status: number; /** * The response data, if any. Note that this will automatically be converted to the proper type */ readonly response: T; /** * The responseType set on the request. (For example: `""`, `"arraybuffer"`, `"blob"`, `"document"`, `"json"`, or `"text"`) * @deprecated There isn't much reason to examine this. It's the same responseType set (or defaulted) on the ajax config. * If you really need to examine this value, you can check it on the `request` or the `xhr`. Will be removed in v8. */ readonly responseType: XMLHttpRequestResponseType; /** * The total number of bytes loaded so far. To be used with {@link total} while * calculating progress. (You will want to set {@link includeDownloadProgress} or * {@link includeDownloadProgress}) */ readonly loaded: number; /** * The total number of bytes to be loaded. To be used with {@link loaded} while * calculating progress. (You will want to set {@link includeDownloadProgress} or * {@link includeDownloadProgress}) */ readonly total: number; /** * A dictionary of the response headers. */ readonly responseHeaders: Record; /** * A normalized response from an AJAX request. To get the data from the response, * you will want to read the `response` property. * * - DO NOT create instances of this class directly. * - DO NOT subclass this class. * * @param originalEvent The original event object from the XHR `onload` event. * @param xhr The `XMLHttpRequest` object used to make the request. This is useful for examining status code, etc. * @param request The request settings used to make the HTTP request. * @param type The type of the event emitted by the {@link ajax} Observable */ constructor( /** * The original event object from the raw XHR event. */ public readonly originalEvent: ProgressEvent, /** * The XMLHttpRequest object used to make the request. * NOTE: It is advised not to hold this in memory, as it will retain references to all of it's event handlers * and many other things related to the request. */ public readonly xhr: XMLHttpRequest, /** * The request parameters used to make the HTTP request. */ public readonly request: AjaxRequest, /** * The event type. This can be used to discern between different events * if you're using progress events with {@link includeDownloadProgress} or * {@link includeUploadProgress} settings in {@link AjaxConfig}. * * The event type consists of two parts: the {@link AjaxDirection} and the * the event type. Merged with `_`, they form the `type` string. The * direction can be an `upload` or a `download` direction, while an event can * be `loadstart`, `progress` or `load`. * * `download_load` is the type of event when download has finished and the * response is available. */ public readonly type: AjaxResponseType = 'download_load' ) { const { status, responseType } = xhr; this.status = status ?? 0; this.responseType = responseType ?? ''; // Parse the response headers in advance for the user. There's really // not a great way to get all of them. So we need to parse the header string // we get back. It comes in a simple enough format: // // header-name: value here // content-type: application/json // other-header-here: some, other, values, or, whatever const allHeaders = xhr.getAllResponseHeaders(); this.responseHeaders = allHeaders ? // Split the header text into lines allHeaders.split('\n').reduce((headers: Record, line) => { // Split the lines on the first ": " as // "key: value". Note that the value could // technically have a ": " in it. const index = line.indexOf(': '); headers[line.slice(0, index)] = line.slice(index + 2); return headers; }, {}) : {}; this.response = getXHRResponse(xhr); const { loaded, total } = originalEvent; this.loaded = loaded; this.total = total; } }