This repository has been archived on 2022-08-14. You can view files and clone it, but cannot push or open issues or pull requests.
outline/app/utils/ApiClient.js

116 lines
2.7 KiB
JavaScript
Raw Normal View History

2017-05-12 00:23:56 +00:00
// @flow
import { map } from 'lodash';
2017-05-30 02:08:03 +00:00
import invariant from 'invariant';
import stores from 'stores';
2016-02-27 21:53:11 +00:00
2017-05-12 00:23:56 +00:00
type Options = {
baseUrl?: string,
};
2016-02-27 21:53:11 +00:00
class ApiClient {
2017-05-12 00:23:56 +00:00
baseUrl: string;
userAgent: string;
constructor(options: Options = {}) {
2017-04-29 21:20:41 +00:00
this.baseUrl = options.baseUrl || '/api';
2017-11-09 08:20:22 +00:00
this.userAgent = 'OutlineFrontend';
2016-02-27 21:53:11 +00:00
}
2018-06-08 04:35:40 +00:00
fetch = async (
2017-05-12 00:23:56 +00:00
path: string,
method: string,
data: ?Object,
options: Object = {}
) => {
2016-02-27 21:53:11 +00:00
let body;
let modifiedPath;
if (method === 'GET') {
2017-05-12 00:23:56 +00:00
if (data) {
modifiedPath = `${path}?${data && this.constructQueryString(data)}`;
} else {
modifiedPath = path;
}
2016-02-27 21:53:11 +00:00
} else if (method === 'POST' || method === 'PUT') {
body = data ? JSON.stringify(data) : undefined;
2016-02-27 21:53:11 +00:00
}
// Construct headers
const headers = new Headers({
Accept: 'application/json',
'Content-Type': 'application/json',
2018-11-04 06:24:44 +00:00
'cache-control': 'no-cache',
pragma: 'no-cache',
2016-02-27 21:53:11 +00:00
});
2017-05-30 02:08:03 +00:00
if (stores.auth.authenticated) {
invariant(stores.auth.token, 'JWT token not set properly');
headers.set('Authorization', `Bearer ${stores.auth.token}`);
2016-02-27 21:53:11 +00:00
}
let response;
try {
response = await fetch(this.baseUrl + (modifiedPath || path), {
method,
body,
headers,
redirect: 'follow',
credentials: 'omit',
cache: 'no-cache',
});
} catch (err) {
if (window.navigator.onLine) {
throw new Error('A network error occurred, try again?');
} else {
throw new Error('No internet connection available');
}
}
2016-02-27 21:53:11 +00:00
2018-06-08 04:35:40 +00:00
if (response.status >= 200 && response.status < 300) {
return response.json();
}
2017-04-27 04:47:03 +00:00
2018-06-08 04:35:40 +00:00
// Handle 401, log out user
if (response.status === 401) {
stores.auth.logout();
return;
}
2017-04-27 04:47:03 +00:00
2018-06-08 04:35:40 +00:00
// Handle failed responses
const error = {};
error.statusCode = response.status;
error.response = response;
2018-11-04 04:47:46 +00:00
try {
const parsed = await response.json();
error.message = parsed.message || '';
error.error = parsed.error;
error.data = parsed.data;
2018-11-04 04:47:46 +00:00
} catch (_err) {
// we're trying to parse an error so JSON may not be valid
}
2018-06-08 04:35:40 +00:00
throw error;
2017-04-27 04:47:03 +00:00
};
2016-02-27 21:53:11 +00:00
2017-09-03 21:20:39 +00:00
get = (path: string, data: ?Object, options?: Object) => {
2016-08-01 16:03:17 +00:00
return this.fetch(path, 'GET', data, options);
2017-04-27 04:47:03 +00:00
};
2016-02-27 21:53:11 +00:00
2017-09-03 21:20:39 +00:00
post = (path: string, data: ?Object, options?: Object) => {
2016-08-01 16:03:17 +00:00
return this.fetch(path, 'POST', data, options);
2017-04-27 04:47:03 +00:00
};
2016-07-23 19:09:50 +00:00
2016-02-27 21:53:11 +00:00
// Helpers
2017-05-12 00:23:56 +00:00
constructQueryString = (data: Object) => {
return map(
data,
(v, k) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`
).join('&');
2016-02-27 21:53:11 +00:00
};
}
export default ApiClient;
// In case you don't want to always initiate, just import with `import { client } ...`
2017-05-30 02:08:03 +00:00
export const client = new ApiClient();