UNPKG

3.21 kBJavaScriptView Raw
1'use strict';
2
3const requestretry = require('requestretry');
4const request = require('request');
5const Promise = require('bluebird');
6const _ = require('lodash');
7const { getRequestId, getAuthenticatedEntity } = require('./correlation');
8const { REQUEST_ID_HEADER, AUTHENTICATED_ENTITY_HEADER } = require('./headers');
9const { envVarBasedStrategy, compositionStrategy, specifcErrorCodesStrategy, RETRY_STATUS_CODES } = require('./requestStrategies');
10
11const maxAttempts = 5;
12const retryDelay = 5000;
13
14function isNetworkError(err) {
15 return _.get(err, 'code') || RETRY_STATUS_CODES.includes(err.statusCode);
16}
17
18function serviceRequest(opt) {
19 opt = opt || {};
20
21 const serviceConfig = opt.serviceConfig;
22 if (!serviceConfig) {
23 throw new Error('Service config not provided');
24 }
25 const serviceBasePath = `${serviceConfig.protocol}://${serviceConfig.uri}:${serviceConfig.port}`;
26 const path = opt.path;
27 const requestOptions = opt.requestOptions || {};
28 const headers = Object.assign({}, requestOptions.headers);
29
30 // overriding the authenticated entity is something that should only be done in rare rare cases
31 // please advise and discuss before overriding it
32 const authenticatedEntity = opt.authenticatedEntity || getAuthenticatedEntity();
33 if (authenticatedEntity) {
34 headers[AUTHENTICATED_ENTITY_HEADER] =
35 authenticatedEntity.encodeToBase64String();
36 }
37 const requestId = getRequestId();
38 if (requestId) {
39 headers[REQUEST_ID_HEADER] = requestId;
40 }
41
42 const systemOptions = {
43 url: `${serviceBasePath}${path}`,
44 headers
45 };
46 const retryOptions = opt.retryStrategy || {
47 retryStrategy: (err, response = {}) => {
48 return envVarBasedStrategy('HTTP_SKIP_RETRY').excludeOnEnvironmentVariableStrategy() &&
49 compositionStrategy(requestretry.RetryStrategies.NetworkError,
50 specifcErrorCodesStrategy)(err, response);
51 },
52 maxAttempts: opt.maxAttempts || maxAttempts,
53 retryDelay: opt.retryDelay || retryDelay
54 };
55
56 if (opt.stream) {
57 return request(systemOptions);
58 } else {
59 systemOptions.json = true;
60 systemOptions.promiseFactory = (resolver) => {
61 return new Promise(resolver);
62 };
63 return requestretry(Object.assign({}, requestOptions, systemOptions, retryOptions))
64 .then((response) => {
65 if (response.statusCode >= 400) {
66 const error = {};
67 error.statusCode = response.statusCode;
68 error.code = response.code;
69 error.message = `${response.statusCode} - ${JSON && JSON.stringify ? JSON.stringify(response.body) : response.body}`;
70 error.attempts = response.attempts;
71 error.error = response.body;
72 error.response = response;
73 throw error;
74 } else {
75 return response;
76 }
77 })
78 .catch((err) => {
79 err.isNetworkError = isNetworkError(err);
80 throw err;
81 });
82 }
83}
84
85module.exports = serviceRequest;