@microsoft/kiota-http-fetchlibrary
Version:
Kiota request adapter implementation with fetch
186 lines • 8.15 kB
JavaScript
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions.js";
import { httpStatusCode, methodStatusCode } from "./options/ChaosHandlerData.js";
import { ChaosStrategy } from "./options/chaosStrategy.js";
/**
*
* Class
* Middleware
* Class representing RedirectHandler
*/
export class ChaosHandler {
/**
*
* To create an instance of ChaosHandler
* @param [options] - The chaos handler options instance
* @param manualMap - The Map passed by user containing url-statusCode info
*/
constructor(options, manualMap) {
/**
* A member holding options to customize the handler behavior
*/
this.options = {
chaosStrategy: ChaosStrategy.RANDOM,
statusMessage: "A random status message",
chaosPercentage: 10,
};
const chaosOptions = Object.assign(this.options, options);
if (chaosOptions.chaosPercentage > 100 || chaosOptions.chaosPercentage < 0) {
throw new Error("Chaos Percentage must be set to a value between 0 and 100.");
}
this.options = chaosOptions;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.manualMap = manualMap !== null && manualMap !== void 0 ? manualMap : new Map();
}
/**
* Fetches a random status code for the RANDOM mode from the predefined array
* @param requestMethod - the API method for the request
* @returns a random status code from a given set of status codes
*/
generateRandomStatusCode(requestMethod) {
const statusCodeArray = methodStatusCode[requestMethod];
return statusCodeArray[Math.floor(Math.random() * statusCodeArray.length)];
}
/**
* Strips out the host url and returns the relative url only
* @param chaosHandlerOptions - The ChaosHandlerOptions object
* @param urlMethod - the complete URL
* @returns the string as relative URL
*/
getRelativeURL(chaosHandlerOptions, urlMethod) {
const baseUrl = chaosHandlerOptions.baseUrl;
if (baseUrl === undefined) {
return urlMethod;
}
return urlMethod.replace(baseUrl, "").trim();
}
/**
* Gets a status code from the options or a randomly generated status code
* @param chaosHandlerOptions - The ChaosHandlerOptions object
* @param requestURL - the URL for the request
* @param requestMethod - the API method for the request
* @returns generated statusCode
*/
getStatusCode(chaosHandlerOptions, requestURL, requestMethod) {
if (chaosHandlerOptions.chaosStrategy === ChaosStrategy.MANUAL) {
if (chaosHandlerOptions.statusCode !== undefined) {
return chaosHandlerOptions.statusCode;
}
else {
// manual mode with no status code, can be a global level or request level without statusCode
const relativeURL = this.getRelativeURL(chaosHandlerOptions, requestURL);
const definedResponses = this.manualMap.get(relativeURL);
if (definedResponses !== undefined) {
// checking Manual Map for exact match
const mapCode = definedResponses.get(requestMethod);
if (mapCode !== undefined) {
return mapCode;
}
// else statusCode would be undefined
}
else {
// checking for regex match if exact match doesn't work
this.manualMap.forEach((value, key) => {
var _a;
const regexURL = new RegExp(key + "$");
if (regexURL.test(relativeURL)) {
const responseCode = (_a = this.manualMap.get(key)) === null || _a === void 0 ? void 0 : _a.get(requestMethod);
if (responseCode !== undefined) {
return responseCode;
}
}
});
}
}
}
// for manual mode status or if the url was not mapped to a code return a random status
return this.generateRandomStatusCode(requestMethod);
}
/**
* Generates a respondy for the chaoe response
* @param chaosHandlerOptions - The ChaosHandlerOptions object
* @param statusCode - the status code for the response
* @returns the response body
*/
createResponseBody(chaosHandlerOptions, statusCode) {
if (chaosHandlerOptions.responseBody) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return chaosHandlerOptions.responseBody;
}
let body;
if (statusCode >= 400) {
const codeMessage = httpStatusCode[statusCode];
const errMessage = chaosHandlerOptions.statusMessage;
body = {
error: {
code: codeMessage,
message: errMessage,
},
};
}
else {
body = {};
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return body;
}
/**
* Composes a new chaotic response code with the configured parameters
* @param url The url of the request
* @param fetchRequestInit The fetch request init object
* @returns a response object with the configured parameters
*/
createChaosResponse(url, fetchRequestInit) {
var _a;
if (fetchRequestInit.method === undefined) {
throw new Error("Request method must be defined.");
}
const requestMethod = fetchRequestInit.method;
const statusCode = this.getStatusCode(this.options, url, requestMethod);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const responseBody = this.createResponseBody(this.options, statusCode);
const stringBody = typeof responseBody === "string" ? responseBody : JSON.stringify(responseBody);
return {
url,
body: stringBody,
status: statusCode,
statusText: this.options.statusMessage,
headers: (_a = this.options.headers) !== null && _a !== void 0 ? _a : {},
};
}
execute(url, requestInit, requestOptions) {
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("chaosHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.chaos.enable", true);
return this.runChaos(url, requestInit, requestOptions);
}
finally {
span.end();
}
});
}
return this.runChaos(url, requestInit, requestOptions);
}
runChaos(url, requestInit, requestOptions, span) {
if (Math.floor(Math.random() * 100) < this.options.chaosPercentage) {
span === null || span === void 0 ? void 0 : span.addEvent(ChaosHandler.chaosHandlerTriggeredEventKey);
return Promise.resolve(this.createChaosResponse(url, requestInit));
}
else {
if (!this.next) {
throw new Error("Please set the next middleware to continue the request");
}
return this.next.execute(url, requestInit, requestOptions);
}
}
}
ChaosHandler.chaosHandlerTriggeredEventKey = "com.microsoft.kiota.chaos_handler_triggered";
//# sourceMappingURL=chaosHandler.js.map