microservice-utilities
Version:
Utilities supporting authorization, request logging and other often reused parts of microservices.
171 lines (153 loc) • 6.29 kB
JavaScript
const axios = require('axios');
const uuid = require('uuid');
const invalidToken = 'Invalid token';
class PlatformClient {
/**
* Constructor
* @param {Function} logFunction log function, defaults to console.log
* @param {Function} tokenResolverFunction optional token resolver function, if provided it will extend the request headers with Bearer token
* @param {Object} options optional object
* @param {Object} options.client axios http client
*/
constructor(logFunction, tokenResolverFunction = null, options = null) {
this.logFunction = logFunction || console.log;
this.tokenResolverFunction = tokenResolverFunction;
let client = options && options.client || axios.create();
client.interceptors.request.use(config => {
config.requestId = uuid.v4();
this.logFunction({
title: 'Platform Request',
level: 'INFO',
requestId: config.requestId,
method: config.method,
url: config.url
}, false);
if (!config.url) {
return Promise.reject({ response: { status: 400, data: { description: 'PlatformClient Error: "url" must be defined', errorCode: 'BadRequest' } } });
}
return config;
}, error => {
let newError = error && error.response && {
data: error.response.data,
status: error.response.status,
headers: error.response.headers
} || error.message && { message: error.message, code: error.code, stack: error.stack } || error;
this.logFunction({
title: 'Platform Request Error',
level: 'WARN',
requestId: error && error.config && error.config.requestId || error.request && error.request.config && error.request.config.requestId,
exception: newError
});
throw newError;
});
client.interceptors.response.use(response => response, error => {
let newError = error && error.response && {
data: error.response.data,
status: error.response.status,
headers: error.response.headers
} || error.message && { message: error.message, code: error.code, stack: error.stack } || error;
let requestId = error && error.config && error.config.requestId || error.request && error.request.config && error.request.config.requestId;
if (error.message === invalidToken) {
this.logFunction({ title: 'Platform call skipped due to a token error', level: 'INFO', requestId: requestId, exception: newError });
} else {
this.logFunction({ title: 'Platform Response Error', level: 'INFO', requestId: requestId, exception: newError });
}
throw newError;
});
this.client = client;
}
async createHeadersWithResolvedToken(headers = {}) {
if (this.tokenResolverFunction) {
if (headers.Authorization) {
throw new Error('Authorization header already specified, please create a new PlatformClient with a different (or without a) tokenResolver');
} else {
let token = await this.tokenResolverFunction();
headers.Authorization = `Bearer ${token}`;
}
}
return headers;
}
/**
* Get from the given url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} headers request headers
* @param {String} type accepted response type
* @return {Promise<Object>}
*/
async get(url, headers, type = 'json') {
return this.client.get(url, {
headers: await this.createHeadersWithResolvedToken(headers),
responseType: type
});
}
/**
* Post data to the given url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} data request data
* @param {Object} headers request headers
* @return {Promise<Object>}
*/
async post(url, data, headers) {
return this.client.post(url, data, {
headers: await this.createHeadersWithResolvedToken(headers)
});
}
/**
* Put data to the given url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} data request data
* @param {Object} headers request headers
* @return {Promise<Object>}
*/
async put(url, data, headers) {
return this.client.put(url, data, {
headers: await this.createHeadersWithResolvedToken(headers)
});
}
/**
* Patch data on the given url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} data request data
* @param {Object} headers request headers
* @return {Promise<Object>}
*/
async patch(url, data, headers) {
return this.client.patch(url, data, {
headers: await this.createHeadersWithResolvedToken(headers)
});
}
/**
* Delete the resource on the given url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} headers request headers
* @return {Promise<Object>}
*/
async delete(url, headers) {
return this.client.delete(url, {
headers: await this.createHeadersWithResolvedToken(headers)
});
}
/**
* Makes a head call to the provided url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} headers request headers
* @return {Promise<Object>}
*/
async head(url, headers) {
return this.client.head(url, {
headers: await this.createHeadersWithResolvedToken(headers)
});
}
/**
* Makes an options call to the provided url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
* @param {String} url to send the request to
* @param {Object} headers request headers
* @return {Promise<Object>}
*/
async options(url, headers) {
return this.client.options(url, {
headers: await this.createHeadersWithResolvedToken(headers)
});
}
}
module.exports = PlatformClient;