UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

346 lines (344 loc) 12.5 kB
import { Observable, throwError } from 'rxjs'; import { ajax } from 'rxjs/ajax'; import { catchError, mergeMap, switchMap } from 'rxjs/operators'; import { Cookie } from './cookie'; import { ErrorExtended } from './error-extended'; import { headerConstants } from './http-constants'; /** * Retry options for an http request */ export class HttpRetryOptions { maxRetry = 0; handlers = []; } /** * Enum for http method types */ export var HttpMethod; (function (HttpMethod) { HttpMethod["Get"] = "GET"; HttpMethod["Post"] = "POST"; HttpMethod["Put"] = "PUT"; HttpMethod["Delete"] = "DELETE"; HttpMethod["Patch"] = "PATCH"; HttpMethod["Head"] = "HEAD"; HttpMethod["Options"] = "OPTIONS"; })(HttpMethod || (HttpMethod = {})); /** * The Http observable based class. */ export class Http { /** * Default ajax options must be used for CORS. */ static defaultHttpOptions = { withCredentials: true, crossDomain: true }; /** * The collection of set of monitors. */ static monitorSets = []; /** * The default retry options. */ defaultRetryOptions = new HttpRetryOptions(); /** * Register the set of monitors. * * @param monitorSet The set of monitors. */ static registerMonitorSet(monitorSet) { const found = Http.monitorSets.find(monitors => monitors.name === monitorSet.name); if (found) { return; } Http.monitorSets.push(monitorSet); } /** * Unregister the set of monitors. * * @param name The name of set of monitors. * @returns boolean true if unregistered the named set. */ static unregisterMonitors(name) { const found = Http.monitorSets.find(monitors => monitors.name === name); if (found) { Http.monitorSets.remove(found); return true; } return false; } /** * The common request method. * Adds default responseType, contentType, Accept values if they are not already included in the request * * @param request the request options. * @param options the retry options. */ request(request, retryOptions) { if (!request) { request = {}; } if (!retryOptions) { retryOptions = this.defaultRetryOptions; } if (!request.headers) { request.headers = {}; } if (!request.responseType) { request.responseType = 'json'; } if (request.headers && !request.headers[headerConstants.CONTENT_TYPE]) { request.headers[headerConstants.CONTENT_TYPE] = 'application/json; charset=utf-8'; } if (request.method === HttpMethod.Get || request.method === HttpMethod.Delete || request.method === HttpMethod.Head) { delete request.headers[headerConstants.CONTENT_TYPE]; request.body = undefined; } if (request.headers && !request.headers[headerConstants.ACCEPT]) { request.headers[headerConstants.ACCEPT] = 'application/json, text/plain, */*'; } if (request.headers && !request.headers[headerConstants.CROSS_SITE_REQUEST_FORGERY_TOKEN]) { const token = Cookie.getCrossSiteRequestForgeryToken(); if (token) { request.headers[headerConstants.CROSS_SITE_REQUEST_FORGERY_TOKEN] = token; } } if (retryOptions.maxRetry > 0 && retryOptions.handlers && retryOptions.handlers.length > 0) { return this.requestWithHandlers(request, retryOptions); } return this.monitorAjax(request); } /** * Performs a request without modification. * If the result is an error, we will retry with the handlers in options * * @param request the request options. * @param options the retry options. * @param count the current iteration of the retry cycle. */ requestWithHandlers(request, retryOptions, count = 0) { return this.monitorAjax(request) .pipe(catchError((error, caught) => { // original request is replaced with latest instance. it must take current error request. const caughtRequest = caught.source.request || (caught.source.source && caught.source.source.value) || request; if (++count > retryOptions.maxRetry) { return throwError(() => error); } const handler = retryOptions.handlers.find(handler2 => handler2.canHandle(error.status, error)); if (handler) { if (handler.handleNoRetry) { return handler.handleNoRetry(error.status, caughtRequest, error) .pipe(mergeMap(() => throwError(() => error))); } else if (handler.handle) { return handler.handle(error.status, caughtRequest, error) .pipe(catchError(handlerError => { // if the handler throws, return the original error with an inserted // property for the handler error error['handlerError'] = handlerError; return throwError(() => error); }), switchMap(() => this.monitorAjax(caughtRequest))); } } return throwError(() => error); })); } /** * Performs a request with `get` http method. * * @param url the url. * @param request the request options. * @param options the retry options. */ get(url, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Get; return this.request(request, options); } /** * Performs a request with `post` http method. * * @param url the url. * @param body the body content. * @param request the request options. * @param options the retry options. */ post(url, body, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Post; request.body = body; return this.request(request, options); } /** * Performs a request with `put` http method. * * @param url the url. * @param body the body content. * @param request the request options. * @param options the retry options. */ put(url, body, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Put; request.body = body; return this.request(request, options); } /** * Performs a request with `delete` http method. * * @param url the url. * @param request the request options. * @param options the retry options. */ delete(url, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Delete; return this.request(request, options); } /** * Performs a request with `patch` http method. * * @param url the url. * @param body the body content. * @param request the request options. * @param options the retry options. */ patch(url, body, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Patch; request.body = body; return this.request(request, options); } /** * Performs a request with `head` http method. * * @param url the url. * @param request the request options. * @param options the retry options. */ head(url, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Head; return this.request(request, options); } /** * Performs a request with `options` http method. * * @param url the url. * @param request the request options. * @param options the retry options. */ options(url, request, options) { request = request ? request : {}; request.url = url; request.method = HttpMethod.Options; return this.request(request, options); } /** * Performs a request with 'get' http method with cache control. * * @param url the uri for GET call. * @return the observable for GET result data. */ getNoCache(url, noCache = true, responseType = '', withCredentials = true) { const publish = new Observable(observer => { const request = new XMLHttpRequest(); const handler = () => { if (request.readyState === XMLHttpRequest.DONE) { if (request.status === 200) { try { let response; if (responseType === '') { response = JSON.parse(request.response); } else { response = request.response; } observer.next({ status: request.status, response }); observer.complete(); } catch (e) { observer.error(e); } } else { const error = new ErrorExtended(request.statusText); error.extendedSource = ErrorExtended.sources.getNoCache; error.extended = { status: request.status, url }; observer.error(error); } } }; request.open('Get', url); request.withCredentials = withCredentials; request.responseType = responseType; request.setRequestHeader(headerConstants.ACCEPT, 'application/json, text/plain, */*'); if (noCache) { request.setRequestHeader('Cache-control', 'no-cache'); } request.onreadystatechange = handler; request.send(); }); return publish; } /** * Performs a request with 'delete' http method without waiting for the response. * * @param url the uri for GET call. */ deleteQuick(url, headers) { const request = new XMLHttpRequest(); request.open('Delete', url); request.withCredentials = true; request.responseType = 'json'; request.setRequestHeader(headerConstants.ACCEPT, 'application/json, text/plain, */*'); request.setRequestHeader(headerConstants.CONTENT_TYPE, 'application/json; charset=utf-8'); request.setRequestHeader(headerConstants.CACHE_CONTROL, 'no-cache'); let xsrf = false; if (headers) { for (const key in headers) { if (key) { request.setRequestHeader(key, headers[key]); if (key.toLowerCase() === headerConstants.CROSS_SITE_REQUEST_FORGERY_TOKEN.toLowerCase()) { xsrf = true; } } } } const token = Cookie.getCrossSiteRequestForgeryToken(); if (token && !xsrf) { request.setRequestHeader(headerConstants.CROSS_SITE_REQUEST_FORGERY_TOKEN, token); } // not watching any response. request.send(); } monitorAjax(request) { let monitored = ajax; for (const monitorSet of Http.monitorSets) { monitored = this.monitor(monitored, monitorSet); } return monitored(request); } monitor(target, monitorSet) { return function (request) { return monitorSet.preMonitor(request) .pipe(switchMap(monitoredRequest => { if (monitoredRequest instanceof Error) { return throwError(() => monitoredRequest); } return target(monitoredRequest).pipe(catchError((error) => { return monitorSet.errorMonitor(error); }), switchMap(response => monitorSet.successMonitor(response))); })); }; } } //# sourceMappingURL=http.js.map