import getEnvelopeBody from './getEnvelopeBody'; import { appendQueryParameters } from './location'; import parseJSON from '../json/parseJson'; import responseHandler from './responseHandler'; import type { NetworkResponse, RequestOptions, SerializableObject } from '../types'; const rnoContent = (method: string): boolean => /^(?:GET|HEAD)$/i.test((method)); const defaultOptions: Partial = { method: 'GET', headers: {}, }; /** * XMLHttpRequest transport */ export default function xhr( o: RequestOptions, ): Promise> { return new Promise((resolve, reject) => { const options = { ...defaultOptions, ...o, }; const method = options.method || 'GET'; const hasContent = !rnoContent(method); const headers = options.headers || {}; const request = new XMLHttpRequest(); let url = options.url || window.location.href; if (!options.envelope && !hasContent && options.data) { url = appendQueryParameters(url, options.data as SerializableObject); } if (options.envelope) { url = appendQueryParameters(url, { envelope: 'request' }); } request.open(options.envelope ? 'POST' : method, url, true); request.onreadystatechange = () => { if (request.readyState === 4) { const response = parseJSON(request.responseText); responseHandler(request.status, response) .then((result) => resolve(result)) .catch((err) => reject(err)); } }; if (options.envelope) { request.send(getEnvelopeBody( method, headers, options.data, )); return; } Object.keys(headers).forEach((header) => { if (Object.prototype.hasOwnProperty.call(headers, header)) { request.setRequestHeader(header, headers[header]); } }); if (hasContent && options.data) { request.setRequestHeader('Content-Type', 'application/json'); request.send(JSON.stringify(options.data)); } else { request.send(); } }); }