Skip to content

Instantly share code, notes, and snippets.

@197291
Created October 26, 2017 06:52
Show Gist options
  • Save 197291/d4d1ef49cfd9719eb2dadd09467e220a to your computer and use it in GitHub Desktop.
Save 197291/d4d1ef49cfd9719eb2dadd09467e220a to your computer and use it in GitHub Desktop.
Api client helper
import superagent from 'superagent';
import cookies from 'react-cookie';
import config from '../config';
import CryptoJS from 'crypto-js';
import _clone from 'lodash/clone';
import { normalizePayload } from 'utils/jwt';
const methods = ['get', 'post', 'put', 'patch', 'del'];
function formatUrl(path) {
const adjustedPath = path[0] !== '/' ? '/' + path : path;
const protocol = (config.apiPort * 1) === 443 ? 'https://' : 'http://';
return protocol + config.apiHost + ':' + config.apiPort + adjustedPath;
}
/* eslint-disable */
const crypting = (body, secret) => {
const hash = CryptoJS.HmacSHA256(body, secret);
return CryptoJS.enc.Base64.stringify(hash);
};
const base64UrlEncode = (body) => {
const wordArray = CryptoJS.enc.Utf8.parse(body);
return CryptoJS.enc.Base64.stringify(wordArray);
};
/* eslint-enable */
export default class ApiClient {
constructor(req) {
methods.forEach((method) =>
this[method] = (path, { params, data, headers, file, withoutToken } = {}) => new Promise((resolve, reject) => {
const request = superagent[method](formatUrl(path));
if (params) {
request.query(params);
}
const header = {
'alg': 'HS256',
'typ': 'JWT'
};
const payload = {
request: []
};
if (params) {
payload.request = normalizePayload(_clone(params));
}
if (data) {
payload.request = _clone(data);
}
if (payload.request.length === undefined && Object.keys(payload.request).length === 0) {
payload.request = [];
}
let token = '';
let team = '';
let locale = '';
let user = '';
let device = '';
if (__SERVER__) {
(req.get('cookie') || '').split(' ').forEach((it) => {
const parsed = it.split('=');
if (parsed[0] === 'auth') {
token = parsed[1].replace(/;/g, '');
console.info('Try preload user with token: ', token);
}
if (parsed[0] === 'team') {
team = parsed[1].replace(/;/g, '');
console.info('Try preload user with team: ', team);
}
if (parsed[0] === 'user') {
user = decodeURIComponent(parsed[1].replace(/;/g, ''));
console.info('Try preload user with email: ', user);
}
if (parsed[0] === 'device') {
device = decodeURIComponent(parsed[1].replace(/;/g, ''));
console.info('Try preload user with device: ', device);
}
});
} else if (!__SERVER__) {
token = cookies.load('auth', { path: '/' });
team = cookies.load('team', { path: '/' });
locale = cookies.load('locale', { path: '/' });
user = cookies.load('user', { path: '/' });
device = cookies.load('device', { path: '/' });
}
payload.email = user;
payload.locale = locale;
payload.team = team;
payload.device = device;
let finalToken = '';
if (token) {
const signature = crypting(base64UrlEncode(JSON.stringify(header)) + '.' + base64UrlEncode(JSON.stringify(payload)), token);
finalToken = base64UrlEncode(JSON.stringify(header)) + '.' + base64UrlEncode(JSON.stringify(payload)) + '.' + signature;
}
if (__SERVER__) {
request.set('USER-AGENT', req.get('User-Agent'));
request.timeout(2000);
}
if (finalToken && !withoutToken) {
request.set('Authorization', 'Bearer ' + finalToken);
}
if (headers) {
Object.keys(headers).forEach((key) => {
request.set(key, headers[key]);
});
}
if (file && !!data) {
for (const key in data) {
if (!data.hasOwnProperty(key)) continue;
request.field(String(key), data[key]);
}
}
if (file) {
if (file instanceof File) {
request.attach('file', file);
} else if (file instanceof FileList) {
for (let index = 0; index < file.length; index++) {
request.attach(`file[]`, file.item(index));
}
} else if (file.content) {
request.attach('file', file.content);
} else {
throw new Error('Incorect upload usage');
}
}
if (data && !file) {
request.send(data);
}
request.end((err, res) => {
if (err) {
return reject(!!res && !!res.body ? Object.assign({}, res.body, {
statusCode: !!res ? res.statusCode : 555
}) : {
text: !!res ? res.text : 'N/A',
statusCode: !!res ? res.statusCode : 555,
error: !!res ? res.error : ''
});
}
return resolve({
body: res.body,
headers: res.headers,
status: res.status
});
});
}));
}
/*
* There's a V8 bug where, when using Babel, exporting classes with only
* constructors sometimes fails. Until it's patched, this is a solution to
* "ApiClient is not defined" from issue #14.
* https://github.com/erikras/react-redux-universal-hot-example/issues/14
*
* Relevant Babel bug (but they claim it's V8): https://phabricator.babeljs.io/T2455
*
* Remove it at your own risk.
*/
empty() {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment