trade360-nodejs-sdk
Version:
LSports Trade360 SDK for Node.js
196 lines • 9.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseHttpClient = void 0;
const axios_1 = require("axios");
const lodash_1 = require("lodash");
const common_1 = require("../common");
const http_response_dto_1 = require("../common/dtos/http-response.dto");
const errors_1 = require("../../entities/errors");
const services_1 = require("./services");
const validators_1 = require("./validators");
const _logger_1 = require("../../logger");
const _utilities_1 = require("../../utilities");
/**
* BaseHttpClient class is responsible for sending requests
* to the REST API. It is a base class for all HTTP clients.
* It contains the basic logic for sending requests.
* @param apiBaseUrl The base URL of the REST API
* @param packageCredentials The package credentials for the API
* @param logger The logger instance to be used for logging
*/
class BaseHttpClient {
constructor({ restApiBaseUrl, packageCredentials, logger }) {
this.requestSettings = validators_1.RequestSettingsValidator.validate({
restApiBaseUrl,
...packageCredentials,
});
this.logger = !(0, lodash_1.isNil)(logger) ? logger : new _logger_1.ConsoleAdapter();
this.baseUrl = encodeURI(restApiBaseUrl);
this.httpService = new services_1.AxiosService(this.baseUrl);
}
/**
* This method is responsible for sending POST requests to
* the customers API. basic POST request, with body contains
* packageId, userName and password.
* The request expect getting generic type R which declare
* the expected response structure.
* @param route string that represent the route expected to
* be sent to the API endpoint.
* @param responseBodyType new instance of the expected response
* structure.
* @param requestBody optional parameter that represent the body
* of the request.
* @returns promise with the TResponse type response type of
* the API.
*/
async postRequest({ route, responseBodyType, requestBody, }) {
this.requestSettings = !(0, lodash_1.isNil)(requestBody)
? requestBody
: _utilities_1.TransformerUtil.transform(this.requestSettings, common_1.HttpRequestDto);
const responsePayloadDto = http_response_dto_1.HttpResponsePayloadDto.createPayloadDto(responseBodyType);
try {
const response = await this.httpService.post(route, this.requestSettings);
return await this.handleValidResponse(response, responsePayloadDto);
}
catch (error) {
this.handleErrorResponse(error, responsePayloadDto);
}
}
/**
* This method is responsible for sending GET requests to the
* customers API. The request expect getting generic type R which
* declare the expected response structure.
* @param route string that represent the route expected to be
* sent to the API endpoint.
* @param responseBodyType new instance of the expected response
* structure.
* @param params optional parameter that represent the query
* parameters of the request.
* @returns promise with the TResponse type response type of the
* API.
*/
async getRequest({ route, responseBodyType, requestBody: params, }) {
this.requestSettings = !(0, lodash_1.isNil)(params)
? params
: _utilities_1.TransformerUtil.transform(this.requestSettings, common_1.HttpRequestDto);
const responsePayloadDto = http_response_dto_1.HttpResponsePayloadDto.createPayloadDto(responseBodyType);
try {
// Build the query string from the request object properties
const queryString = this.buildQueryString(params);
const fullUri = `${route}?${queryString}`;
const httpResponse = await this.httpService.get(fullUri);
return await this.handleValidResponse(httpResponse, responsePayloadDto);
}
catch (error) {
this.handleErrorResponse(error, responsePayloadDto);
}
}
/**
* This method is responsible for handling the valid response.
* @param httpResponse The response received from the API call
* @param responsePayloadDto The response payload DTO to be used
* for transforming the response
* @returns The response payload DTO with the required properties
* @throws HttpResponseError if the response does not contain the
* required properties
*/
async handleValidResponse(httpResponse, responsePayloadDto) {
const { data } = httpResponse;
const responsePayload = _utilities_1.TransformerUtil.transform(data, responsePayloadDto);
this.validateResponsePayloadStructure(responsePayload);
return responsePayload.body;
}
/**
* This method is responsible for validating the structure of the
* response payload. It checks if the response payload contains the
* required properties.
* @param responsePayload The response payload to be validated
* @returns void if the response payload contains the required
* properties
* @throws HttpResponseError if the response payload does not contain
* the required properties
*/
validateResponsePayloadStructure(responsePayload) {
const { header, body } = responsePayload;
if ((0, lodash_1.isNil)(header)) {
throw new errors_1.HttpResponseError("'Header' property is missing. Please ensure that you use the correct URL.");
}
if ((0, lodash_1.isNil)(body)) {
throw new errors_1.HttpResponseError("'Body' property is missing. Please ensure that you use the correct URL.");
}
}
/**
* This method is responsible for handling the error response.
* It throws an error with the appropriate message based on the error
* response received. If the error response is not an AxiosError, it
* throws the error as is.
* @param errorResponse The error response received from the API call
* @param responsePayloadDto The response payload DTO to be used for
* transforming the error response
* @returns void if the error response is handled successfully
* @throws HttpResponseError if the error response contains errors in
* the response body, it throws an error with the error messages as
* the context of the error response
* @throws HttpResponseError if the error response is not an AxiosError
* or if the error response is an AxiosError with a status code that is
* not handled by the HttpResponseError class
*/
handleErrorResponse(errorResponse, responsePayloadDto) {
if ((0, lodash_1.isNil)(errorResponse)) {
throw new errors_1.HttpResponseError('', { context: 'No response received' });
}
else if (!(errorResponse instanceof axios_1.AxiosError))
throw errorResponse;
const { response, message, cause } = errorResponse;
const rawErrorResponse = errorResponse.toString();
if ((0, lodash_1.isNil)(response)) {
throw new errors_1.HttpResponseError(`with message: ${message}`, {
context: rawErrorResponse,
cause,
});
}
const { data, statusText } = response;
if ((0, lodash_1.isNil)(data)) {
throw errors_1.HttpResponseError.getHttpResponseErrorByStatusCode(undefined, rawErrorResponse, statusText, message);
}
const transformed = _utilities_1.TransformerUtil.transform(data, responsePayloadDto);
if (!transformed.header) {
throw new errors_1.HttpResponseError("Missing 'header' in error response", { context: data });
}
const { httpStatusCode, errors } = transformed.header;
if (!(0, lodash_1.isNil)(errors)) {
const errorsArray = (0, lodash_1.map)(errors, (error) => error.message);
throw new errors_1.HttpResponseError('', {
context: errorsArray,
cause: errorResponse,
});
}
throw errors_1.HttpResponseError.getHttpResponseErrorByStatusCode(httpStatusCode, rawErrorResponse, statusText, message);
}
/**
* This method is responsible for building the query string from the
* request parameters.
* @param requestParams The request parameters to be used for building
* the query string
* @returns The query string built from the request parameters or an
*
*/
buildQueryString(requestParams) {
if ((0, lodash_1.isNil)(requestParams))
return '';
const queryParams = [];
(0, lodash_1.forEach)(requestParams, (value, key) => {
if ((0, lodash_1.isArray)(value)) {
(0, lodash_1.forEach)(value, (element) => {
queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(element))}`);
});
}
else if (!(0, lodash_1.isNil)(value)) {
queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
}
});
return queryParams.join('&');
}
}
exports.BaseHttpClient = BaseHttpClient;
//# sourceMappingURL=base-http-client.js.map