Created
October 26, 2017 06:52
-
-
Save 197291/d4d1ef49cfd9719eb2dadd09467e220a to your computer and use it in GitHub Desktop.
Api client helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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