fabric-ias
Version:
Node.JS Service for Microsoft Fabric supporting infrastructure as code
189 lines (179 loc) • 6.92 kB
JavaScript
;
const merge = require('deepmerge');
const axios = require("axios");
const delay = require("./utils/delay");
/**
* @class Base
* @classdesc
* Base class for interacting with the Microsoft Fabric API.
* Provides common functionality for API clients, including:
* - Storing the OAuth handler for authentication.
* - Defining the base API endpoint.
* - Providing standard content types for requests.
* - Generating request options with appropriate headers.
* - Standardized error handling for API requests.
*
* @property {AzOauth} OAuth - The OAuth handler instance.
* @property {string} endpoint - The base URL for the Fabric API.
* @property {Object} ContentType - Common content types used in API requests.
* @property {Function|null} ErrorHandler - Optional custom error handler.
*/
class Base {
/**
* Constructs a Base instance for Microsoft Fabric API interaction.
* @param {AzOauth} OAuthHandler - An object responsible for handling OAuth authentication.
* @param {Function|null} [ErrorHandler=null] - Optional custom error handler function.
*/
constructor(OAuthHandler, ErrorHandler = null, retryAfter = 20000) {
this.OAuth = OAuthHandler;
this.ErrorHandler = ErrorHandler;
this.endpoint = `https://api.fabric.microsoft.com/v1`;
this._retry = retryAfter;
this.ContentType = {
JSON: 'application/json',
FormUrlEncoded: 'application/x-www-form-urlencoded',
Multipart: 'multipart/form-data'
};
}
/**
* Calls delay to hold processing for a specified time.
* @param {int} ts - The time in milliseconds to wait before proceeding.
* @returns
*/
async wait(ts = null) {
await delay(ts || this._retry);
return this;
}
/**
* Generates request options with authorization and content-type headers.
* Merges any additional options provided.
*
* @async
* @param {Object} [options={}] - Additional request options to merge with defaults.
* @returns {Promise<Object>} The merged options object with headers set for authorization and content type.
*/
async Options(options = {}) {
const defaults = {
headers: {
'Content-Type': this.ContentType.JSON,
'Authorization': await this.OAuth.authorization()
}
};
return merge.all([defaults, options]);
}
/**
* Sends a GET request to the specified endpoint.
* @param {string} endpoint - The API endpoint path (relative to base).
* @param {Object} [options={}] - Additional request options.
* @param {function} [validator=null] - Validation Callback function to validate the resp.
* @returns {Promise<Object>} The Axios resp object.
* @throws {Error} If the request fails.
*/
async _get(endpoint, options = {}, validator = null) {
const opts = await this.Options(options);
try {
const resp = await axios.get(`${this.endpoint}${endpoint}`, opts);
if (validator) validator(resp);
return resp;
} catch (error) {
this.parseError(error);
}
}
/**
* Sends a POST request to the specified endpoint.
* @param {string} endpoint - The API endpoint path (relative to base).
* @param {Object} [data={}] - The request payload.
* @param {Object} [options={}] - Additional request options.
* @param {function} [validator=null] - Validation Callback function to validate the resp.
* @returns {Promise<Object>} The Axios resp object.
* @throws {Error} If the request fails.
*/
async _post(endpoint, data = {}, options = {}, validator = null) {
const opts = await this.Options(options);
try {
const resp = await axios.post(`${this.endpoint}${endpoint}`, data, opts);
if (validator) validator(resp);
return resp;
} catch (error) {
this.parseError(error);
}
}
/**
* Sends a PUT request to the specified endpoint.
* @param {string} endpoint - The API endpoint path (relative to base).
* @param {Object} [data={}] - The request payload.
* @param {Object} [options={}] - Additional request options.
* @param {function} [validator=null] - Validation Callback function to validate the resp.
* @returns {Promise<Object>} The Axios resp object.
* @throws {Error} If the request fails.
*/
async _put(endpoint, data = {}, options = {}, validator = null) {
const opts = await this.Options(options);
try {
const resp = await axios.put(`${this.endpoint}${endpoint}`, data, opts);
if (validator) validator(resp);
return resp;
} catch (error) {
this.parseError(error);
}
}
/**
* Sends a DELETE request to the specified endpoint.
* @param {string} endpoint - The API endpoint path (relative to base).
* @param {Object} [options={}] - Additional request options.
* @param {function} [validator=null] - Validation Callback function to validate the resp.
* @returns {Promise<Object>} The Axios resp object.
* @throws {Error} If the request fails.
*/
async _delete(endpoint, options = {}, validator = null) {
const opts = await this.Options(options);
try {
const resp = await axios.delete(`${this.endpoint}${endpoint}`, opts);
if (validator) validator(resp);
return resp;
} catch (error) {
this.parseError(error);
}
}
/**
* Sends a PATCH request to the specified endpoint.
* @param {string} endpoint - The API endpoint path (relative to base).
* @param {Object} [data={}] - The request payload.
* @param {Object} [options={}] - Additional request options.
* @param {function} [validator=null] - Validation Callback function to validate the resp.
* @returns {Promise<Object>} The Axios resp object.
* @throws {Error} If the request fails.
*/
async _patch(endpoint, data = {}, options = {}, validator = null) {
const opts = await this.Options(options);
try {
const resp = await axios.patch(`${this.endpoint}${endpoint}`, data, opts);
if (validator) validator(resp);
return resp;
} catch (error) {
this.parseError(error);
}
}
/**
* Handles errors from Axios requests.
* If a custom ErrorHandler is provided, it will be called.
* Otherwise, throws a formatted error.
* @param {Error} error - The error object thrown by Axios.
* @throws {Error} The formatted error.
*/
parseError(error) {
if (error.resp && error.resp.data && error.resp.data.errorCode && error.resp.data.message) {
if (this.ErrorHandler) {
this.ErrorHandler(`${error.resp.data.errorCode}: ${error.resp.data.message}`, error.resp.data);
return;
}
throw Error(`${error.resp.data.errorCode}: ${error.resp.data.message}`);
}
if (this.ErrorHandler) {
this.ErrorHandler(`${error.message}`, error);
return;
}
throw Error(error.message);
}
}
module.exports = Base;