2016-05-03 07:32:40 +00:00
|
|
|
import _map from 'lodash/map';
|
2016-06-26 06:31:22 +00:00
|
|
|
import stores from 'stores';
|
2016-02-27 21:53:11 +00:00
|
|
|
|
2016-04-29 05:25:37 +00:00
|
|
|
import constants from '../constants';
|
2016-02-27 21:53:11 +00:00
|
|
|
|
|
|
|
class ApiClient {
|
|
|
|
constructor(options = {}) {
|
2016-04-29 05:25:37 +00:00
|
|
|
this.baseUrl = options.baseUrl || constants.API_BASE_URL;
|
|
|
|
this.userAgent = options.userAgent || constants.API_USER_AGENT;
|
2016-02-27 21:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fetch = (path, method, data) => {
|
|
|
|
let body;
|
|
|
|
let modifiedPath;
|
|
|
|
|
|
|
|
if (method === 'GET') {
|
2016-07-22 07:11:54 +00:00
|
|
|
modifiedPath = `${path}?${this.constructQueryString(data)}`;
|
2016-02-27 21:53:11 +00:00
|
|
|
} else if (method === 'POST' || method === 'PUT') {
|
|
|
|
body = JSON.stringify(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct headers
|
|
|
|
const headers = new Headers({
|
|
|
|
Accept: 'application/json',
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
'User-Agent': this.userAgent,
|
|
|
|
});
|
2016-06-26 06:31:22 +00:00
|
|
|
if (stores.user.authenticated) {
|
|
|
|
headers.set('Authorization', `Bearer ${stores.user.token}`);
|
2016-02-27 21:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Construct request
|
|
|
|
const request = fetch(this.baseUrl + (modifiedPath || path), {
|
|
|
|
method,
|
|
|
|
body,
|
|
|
|
headers,
|
|
|
|
redirect: 'follow',
|
|
|
|
});
|
|
|
|
|
|
|
|
// Handle request promises and return a new promise
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
request
|
|
|
|
.then((response) => {
|
|
|
|
// Handle successful responses
|
|
|
|
if (response.status >= 200 && response.status < 300) {
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle 401, log out user
|
|
|
|
if (response.status === 401) {
|
2016-06-26 06:31:22 +00:00
|
|
|
stores.user.logout();
|
2016-02-27 21:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle failed responses
|
|
|
|
let error;
|
|
|
|
try {
|
|
|
|
// Expect API to return JSON
|
|
|
|
error = JSON.parse(response);
|
|
|
|
} catch (e) {
|
|
|
|
// Expect call to fail without JSON response
|
|
|
|
error = { error: response.statusText };
|
|
|
|
}
|
|
|
|
|
|
|
|
error.statusCode = response.status;
|
|
|
|
error.response = response;
|
|
|
|
reject(error);
|
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
return response.json();
|
|
|
|
})
|
|
|
|
.then((json) => {
|
|
|
|
resolve(json);
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
reject({ error: 'Unknown error' });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
post = (path, data) => {
|
2016-07-22 07:11:54 +00:00
|
|
|
return this.fetch(path, 'GET', data);
|
2016-02-27 21:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
|
|
|
constructQueryString = (data) => {
|
2016-05-03 07:32:40 +00:00
|
|
|
return _map(data, (v, k) => {
|
2016-02-27 21:53:11 +00:00
|
|
|
return `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;
|
|
|
|
}).join('&');
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export default ApiClient;
|
|
|
|
|
|
|
|
// In case you don't want to always initiate, just import with `import { client } ...`
|
|
|
|
const client = new ApiClient();
|
|
|
|
export { client };
|