@infineit-nestjs/services 1.0.39 → 1.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/services/http.client.service.d.ts +2 -0
- package/dist/cjs/services/http.client.service.js +1 -1
- package/dist/es/services/http.client.service.d.ts +2 -0
- package/dist/es/services/http.client.service.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/services/http.client.service.d.ts +3 -1
- package/dist/types/services/index.d.ts +1 -1
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpException } from '@nestjs/common';
|
|
1
2
|
import { ConfigService } from '@nestjs/config';
|
|
2
3
|
import { LoggerService } from './logger.service';
|
|
3
4
|
export declare class HttpServiceClient {
|
|
@@ -17,3 +18,4 @@ export declare class HttpServiceClient {
|
|
|
17
18
|
getMultipleResources(services: string[], method: 'get' | 'post' | 'patch' | 'delete', endpoint: string, data?: any): Promise<any[]>;
|
|
18
19
|
getMultipleResourcesInBatch(services: string[], method: 'get' | 'post' | 'patch' | 'delete', endpoint: string, data?: any): Promise<any[]>;
|
|
19
20
|
}
|
|
21
|
+
export declare function rethrowHttpByStatus(error: HttpException): never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.HttpServiceClient=void 0;const e=require("tslib"),t=require("@nestjs/common"),r=require("@nestjs/config"),s=e.__importDefault(require("axios")),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.HttpServiceClient=void 0,exports.rethrowHttpByStatus=u;const e=require("tslib"),t=require("@nestjs/common"),r=require("@nestjs/config"),s=e.__importDefault(require("axios")),o=e.__importStar(require("axios-retry")),i=e.__importDefault(require("opossum")),c=require("prom-client"),n=require("./logger.service");let a=class{constructor(e,t){this.configService=e,this.loggerService=t,this.configureMetrics(),this.configureAxiosRetry(),this.configureCircuitBreaker()}configureMetrics(){this.requestCounter=new c.Counter({name:"service_client_requests_total",help:"Total number of requests made by the service client",labelNames:["service","method","status"]}),this.responseTimeHistogram=new c.Histogram({name:"service_client_response_time_seconds",help:"Response times of service client requests",labelNames:["service","method","status"],buckets:[.1,.5,1,2,5,10]})}configureAxiosRetry(){(0,o.default)(s.default,{retries:this.configService.getOrThrow("httpmicroservice.axios_retry_count"),retryDelay:e=>1e3*Math.pow(2,e),retryCondition:e=>{const t=e?.response?.status;return(0,o.isNetworkError)(e)||"number"==typeof t&&t>=500&&t<600},onRetry:(e,t,r)=>{this.loggerService.warn(`Retry attempt #${e} for request to ${r.url}`,{sourceClass:this.constructor.name})}})}configureCircuitBreaker(){this.circuitBreaker=new i.default(this.callService.bind(this),{timeout:this.configService.getOrThrow("httpmicroservice.circuit_breaker_timeout"),errorThresholdPercentage:this.configService.getOrThrow("httpmicroservice.circuit_breaker_error_threshold"),resetTimeout:this.configService.getOrThrow("httpmicroservice.circuit_breaker_reset_timeout"),errorFilter:e=>e instanceof t.HttpException?e.getStatus()<500:!(!e?.response?.status||"number"!=typeof e.response.status)&&e.response.status<500}),this.circuitBreaker.fallback((...e)=>{const r=e[e.length-1];if(this.loggerService.warn("Circuit breaker open. Fallback activated.",{sourceClass:this.constructor.name}),r instanceof t.HttpException)throw r;throw new t.ServiceUnavailableException({message:r?.message||"Service is currently unavailable",error:r})})}async callService(e,r,o,i){const c={method:r,url:`${e}/${o}`,timeout:this.configService.getOrThrow("httpmicroservice.request_timeout")};"get"===r?c.params=i:c.data=i,this.requestCounter?.labels(e,r,"pending").inc();const n=Date.now();try{const t=await(0,s.default)(c),i=Date.now()-n;return this.responseTimeHistogram?.labels(e,r,"success").observe(i/1e3),this.requestCounter?.labels(e,r,"success").inc(),this.loggerService.info(`Successfully retrieved data from ${o} at ${e} in ${i}ms.`,{sourceClass:this.constructor.name}),t.data}catch(s){const o=Date.now()-n;this.responseTimeHistogram?.labels(e,r,"failure").observe(o/1e3),this.loggerService.error(`Error calling service at ${e}: ${s.message}`,{sourceClass:this.constructor.name});const i=s instanceof t.HttpException?s.getStatus():s?.response?.status;throw"number"==typeof i&&i<500&&u(s),this.handleServiceError(s)}}handleServiceError(e){if(e.response){const{status:r,data:s}=e.response;return new t.HttpException(s||"Service Error",r)}return e.request?new t.HttpException("Service is currently unavailable",t.HttpStatus.SERVICE_UNAVAILABLE):e instanceof t.HttpException?e:new t.HttpException(e?.message||"Unexpected Error",t.HttpStatus.INTERNAL_SERVER_ERROR)}async getResource(e,r,s,o){const i=this.getServiceBaseURL(e);try{return await(this.circuitBreaker?.fire(i,r,s,o))}catch(r){const o=r;if(this.loggerService.error(`Error occurred while calling ${e} service at ${i}/${s}: ${o.message||o}`,{sourceClass:this.constructor.name}),r instanceof t.HttpException)throw r;throw new t.HttpException(`Service call to ${e} failed: ${o.message||"Service temporarily unavailable"}`,t.HttpStatus.SERVICE_UNAVAILABLE)}}getServiceBaseURL(e){const t=`httpmicroservice.${e}_microservice_url`,r=this.configService.getOrThrow(t);if(!r)throw new Error(`Service URL not found for service: ${e}. Please check your configuration.`);return r}async getMultipleResources(e,t,r,s){const o=e.map(e=>this.getResource(e,t,r,s));return await Promise.all(o)}async getMultipleResourcesInBatch(e,r,s,o){let i=[];for(let c=0;c<e.length;c+=5){const n=e.slice(c,c+5);try{const e=n.map(e=>this.getResource(e,r,s,o)),t=await Promise.all(e);i=[...i,...t]}catch(e){throw this.loggerService.error("Error fetching data for batch",{sourceClass:this.constructor.name,error:e instanceof Error?e:new Error(String(e))}),new t.HttpException("Batch request failed",t.HttpStatus.INTERNAL_SERVER_ERROR)}}return i}};function u(e){let r,s;if(e instanceof t.HttpException)r=e.getStatus(),s=e.getResponse();else{if("object"!=typeof e||null===e||!("response"in e)||"number"!=typeof e.response?.status)throw new t.InternalServerErrorException(e?.message||"Unexpected error");{const t=e;r=t.response.status,s=t.response.data||"Unknown error"}}switch(r){case t.HttpStatus.BAD_REQUEST:throw new t.BadRequestException(s);case t.HttpStatus.UNAUTHORIZED:throw new t.UnauthorizedException(s);case t.HttpStatus.FORBIDDEN:throw new t.ForbiddenException(s);case t.HttpStatus.NOT_FOUND:throw new t.NotFoundException(s);case t.HttpStatus.CONFLICT:throw new t.ConflictException(s);case t.HttpStatus.METHOD_NOT_ALLOWED:throw new t.MethodNotAllowedException(s);case t.HttpStatus.REQUEST_TIMEOUT:throw new t.RequestTimeoutException(s);case t.HttpStatus.SERVICE_UNAVAILABLE:throw new t.ServiceUnavailableException(s);case t.HttpStatus.GATEWAY_TIMEOUT:throw new t.GatewayTimeoutException(s);case t.HttpStatus.INTERNAL_SERVER_ERROR:throw new t.InternalServerErrorException(s);default:throw new t.HttpException(s,r)}}exports.HttpServiceClient=a,exports.HttpServiceClient=a=e.__decorate([(0,t.Injectable)(),e.__metadata("design:paramtypes",[r.ConfigService,n.LoggerService])],a);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpException } from '@nestjs/common';
|
|
1
2
|
import { ConfigService } from '@nestjs/config';
|
|
2
3
|
import { LoggerService } from './logger.service';
|
|
3
4
|
export declare class HttpServiceClient {
|
|
@@ -17,3 +18,4 @@ export declare class HttpServiceClient {
|
|
|
17
18
|
getMultipleResources(services: string[], method: 'get' | 'post' | 'patch' | 'delete', endpoint: string, data?: any): Promise<any[]>;
|
|
18
19
|
getMultipleResourcesInBatch(services: string[], method: 'get' | 'post' | 'patch' | 'delete', endpoint: string, data?: any): Promise<any[]>;
|
|
19
20
|
}
|
|
21
|
+
export declare function rethrowHttpByStatus(error: HttpException): never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,"__esModule",{value:!0}),exports.HttpServiceClient=void 0;const e=require("tslib"),t=require("@nestjs/common"),r=require("@nestjs/config"),s=e.__importDefault(require("axios")),
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.HttpServiceClient=void 0,exports.rethrowHttpByStatus=u;const e=require("tslib"),t=require("@nestjs/common"),r=require("@nestjs/config"),s=e.__importDefault(require("axios")),o=e.__importStar(require("axios-retry")),i=e.__importDefault(require("opossum")),c=require("prom-client"),n=require("./logger.service");let a=class{constructor(e,t){this.configService=e,this.loggerService=t,this.configureMetrics(),this.configureAxiosRetry(),this.configureCircuitBreaker()}configureMetrics(){this.requestCounter=new c.Counter({name:"service_client_requests_total",help:"Total number of requests made by the service client",labelNames:["service","method","status"]}),this.responseTimeHistogram=new c.Histogram({name:"service_client_response_time_seconds",help:"Response times of service client requests",labelNames:["service","method","status"],buckets:[.1,.5,1,2,5,10]})}configureAxiosRetry(){(0,o.default)(s.default,{retries:this.configService.getOrThrow("httpmicroservice.axios_retry_count"),retryDelay:e=>1e3*Math.pow(2,e),retryCondition:e=>{const t=e?.response?.status;return(0,o.isNetworkError)(e)||"number"==typeof t&&t>=500&&t<600},onRetry:(e,t,r)=>{this.loggerService.warn(`Retry attempt #${e} for request to ${r.url}`,{sourceClass:this.constructor.name})}})}configureCircuitBreaker(){this.circuitBreaker=new i.default(this.callService.bind(this),{timeout:this.configService.getOrThrow("httpmicroservice.circuit_breaker_timeout"),errorThresholdPercentage:this.configService.getOrThrow("httpmicroservice.circuit_breaker_error_threshold"),resetTimeout:this.configService.getOrThrow("httpmicroservice.circuit_breaker_reset_timeout"),errorFilter:e=>e instanceof t.HttpException?e.getStatus()<500:!(!e?.response?.status||"number"!=typeof e.response.status)&&e.response.status<500}),this.circuitBreaker.fallback((...e)=>{const r=e[e.length-1];if(this.loggerService.warn("Circuit breaker open. Fallback activated.",{sourceClass:this.constructor.name}),r instanceof t.HttpException)throw r;throw new t.ServiceUnavailableException({message:r?.message||"Service is currently unavailable",error:r})})}async callService(e,r,o,i){const c={method:r,url:`${e}/${o}`,timeout:this.configService.getOrThrow("httpmicroservice.request_timeout")};"get"===r?c.params=i:c.data=i,this.requestCounter?.labels(e,r,"pending").inc();const n=Date.now();try{const t=await(0,s.default)(c),i=Date.now()-n;return this.responseTimeHistogram?.labels(e,r,"success").observe(i/1e3),this.requestCounter?.labels(e,r,"success").inc(),this.loggerService.info(`Successfully retrieved data from ${o} at ${e} in ${i}ms.`,{sourceClass:this.constructor.name}),t.data}catch(s){const o=Date.now()-n;this.responseTimeHistogram?.labels(e,r,"failure").observe(o/1e3),this.loggerService.error(`Error calling service at ${e}: ${s.message}`,{sourceClass:this.constructor.name});const i=s instanceof t.HttpException?s.getStatus():s?.response?.status;throw"number"==typeof i&&i<500&&u(s),this.handleServiceError(s)}}handleServiceError(e){if(e.response){const{status:r,data:s}=e.response;return new t.HttpException(s||"Service Error",r)}return e.request?new t.HttpException("Service is currently unavailable",t.HttpStatus.SERVICE_UNAVAILABLE):e instanceof t.HttpException?e:new t.HttpException(e?.message||"Unexpected Error",t.HttpStatus.INTERNAL_SERVER_ERROR)}async getResource(e,r,s,o){const i=this.getServiceBaseURL(e);try{return await(this.circuitBreaker?.fire(i,r,s,o))}catch(r){const o=r;if(this.loggerService.error(`Error occurred while calling ${e} service at ${i}/${s}: ${o.message||o}`,{sourceClass:this.constructor.name}),r instanceof t.HttpException)throw r;throw new t.HttpException(`Service call to ${e} failed: ${o.message||"Service temporarily unavailable"}`,t.HttpStatus.SERVICE_UNAVAILABLE)}}getServiceBaseURL(e){const t=`httpmicroservice.${e}_microservice_url`,r=this.configService.getOrThrow(t);if(!r)throw new Error(`Service URL not found for service: ${e}. Please check your configuration.`);return r}async getMultipleResources(e,t,r,s){const o=e.map(e=>this.getResource(e,t,r,s));return await Promise.all(o)}async getMultipleResourcesInBatch(e,r,s,o){let i=[];for(let c=0;c<e.length;c+=5){const n=e.slice(c,c+5);try{const e=n.map(e=>this.getResource(e,r,s,o)),t=await Promise.all(e);i=[...i,...t]}catch(e){throw this.loggerService.error("Error fetching data for batch",{sourceClass:this.constructor.name,error:e instanceof Error?e:new Error(String(e))}),new t.HttpException("Batch request failed",t.HttpStatus.INTERNAL_SERVER_ERROR)}}return i}};function u(e){let r,s;if(e instanceof t.HttpException)r=e.getStatus(),s=e.getResponse();else{if("object"!=typeof e||null===e||!("response"in e)||"number"!=typeof e.response?.status)throw new t.InternalServerErrorException(e?.message||"Unexpected error");{const t=e;r=t.response.status,s=t.response.data||"Unknown error"}}switch(r){case t.HttpStatus.BAD_REQUEST:throw new t.BadRequestException(s);case t.HttpStatus.UNAUTHORIZED:throw new t.UnauthorizedException(s);case t.HttpStatus.FORBIDDEN:throw new t.ForbiddenException(s);case t.HttpStatus.NOT_FOUND:throw new t.NotFoundException(s);case t.HttpStatus.CONFLICT:throw new t.ConflictException(s);case t.HttpStatus.METHOD_NOT_ALLOWED:throw new t.MethodNotAllowedException(s);case t.HttpStatus.REQUEST_TIMEOUT:throw new t.RequestTimeoutException(s);case t.HttpStatus.SERVICE_UNAVAILABLE:throw new t.ServiceUnavailableException(s);case t.HttpStatus.GATEWAY_TIMEOUT:throw new t.GatewayTimeoutException(s);case t.HttpStatus.INTERNAL_SERVER_ERROR:throw new t.InternalServerErrorException(s);default:throw new t.HttpException(s,r)}}exports.HttpServiceClient=a,exports.HttpServiceClient=a=e.__decorate([(0,t.Injectable)(),e.__metadata("design:paramtypes",[r.ConfigService,n.LoggerService])],a);
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Argon2Service } from './services/argon2.service.js';
|
|
2
2
|
export { DataTransformerService } from './services/data.transformer.service.js';
|
|
3
3
|
export { EntityActionService } from './services/entity.action.service.js';
|
|
4
|
-
export { HttpServiceClient } from './services/http.client.service.js';
|
|
4
|
+
export { HttpServiceClient, rethrowHttpByStatus } from './services/http.client.service.js';
|
|
5
5
|
export { InitKafkaConsumer } from './services/kafka.microservice.js';
|
|
6
6
|
export { ILogData, LogLevel, LoggerService } from './services/logger.service.js';
|
|
7
7
|
export { MergeService } from './services/merge.service.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpException } from '@nestjs/common';
|
|
1
2
|
import { ConfigService } from '@nestjs/config';
|
|
2
3
|
import { LoggerService } from './logger.service.js';
|
|
3
4
|
|
|
@@ -18,5 +19,6 @@ declare class HttpServiceClient {
|
|
|
18
19
|
getMultipleResources(services: string[], method: 'get' | 'post' | 'patch' | 'delete', endpoint: string, data?: any): Promise<any[]>;
|
|
19
20
|
getMultipleResourcesInBatch(services: string[], method: 'get' | 'post' | 'patch' | 'delete', endpoint: string, data?: any): Promise<any[]>;
|
|
20
21
|
}
|
|
22
|
+
declare function rethrowHttpByStatus(error: HttpException): never;
|
|
21
23
|
|
|
22
|
-
export { HttpServiceClient };
|
|
24
|
+
export { HttpServiceClient, rethrowHttpByStatus };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Argon2Service } from './argon2.service.js';
|
|
2
2
|
export { DataTransformerService } from './data.transformer.service.js';
|
|
3
3
|
export { EntityActionService } from './entity.action.service.js';
|
|
4
|
-
export { HttpServiceClient } from './http.client.service.js';
|
|
4
|
+
export { HttpServiceClient, rethrowHttpByStatus } from './http.client.service.js';
|
|
5
5
|
export { InitKafkaConsumer } from './kafka.microservice.js';
|
|
6
6
|
export { ILogData, LogLevel, LoggerService } from './logger.service.js';
|
|
7
7
|
export { MergeService } from './merge.service.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infineit-nestjs/services",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"main": "./dist/cjs/index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -114,5 +114,5 @@
|
|
|
114
114
|
"node": ">=18.0.0",
|
|
115
115
|
"npm": ">=9.0.0"
|
|
116
116
|
},
|
|
117
|
-
"gitHead": "
|
|
117
|
+
"gitHead": "a00f66cd35874d19a6384017260a93573359072a"
|
|
118
118
|
}
|