GT2/GT2-iOS/node_modules/xdl/build/ApiV2.js.flow

188 lines
4.3 KiB
Plaintext

/**
* @flow
*/
import _ from 'lodash';
import ExtendableError from 'es6-error';
import QueryString from 'querystring';
import axios from 'axios';
import idx from 'idx';
import Config from './Config';
import logger from './Logger';
import type { User } from './User';
let ROOT_BASE_URL = `${Config.api.scheme}://${Config.api.host}`;
if (Config.api.port) {
ROOT_BASE_URL += ':' + Config.api.port;
}
const API_BASE_URL = ROOT_BASE_URL + '/--/api/v2';
export class ApiV2Error extends ExtendableError {
code: string;
details: Object;
serverStack: ?string;
constructor(message: string, code: string = 'UNKNOWN') {
super(message);
this.code = code;
this._isApiError = true;
}
}
type RequestOptions = {
httpMethod: 'get' | 'post' | 'put',
queryParameters?: ?QueryParameters,
body?: ?Object,
json?: boolean,
};
type QueryParameters = { [key: string]: ?(string | number | boolean) };
type ErrorWithResponseBody = Error & {
responseBody?: any,
};
type APIV2ClientOptions = {
idToken?: string,
accessToken?: string,
};
export default class ApiV2Client {
idToken: ?string = null;
accessToken: ?string = null;
static clientForUser(user: ?User): ApiV2Client {
if (user) {
return new ApiV2Client({
accessToken: user.accessToken,
idToken: user.idToken,
});
}
return new ApiV2Client();
}
constructor(options: APIV2ClientOptions = {}) {
if (options.idToken) {
this.idToken = options.idToken;
}
if (options.accessToken) {
this.accessToken = options.accessToken;
}
}
async getAsync(
methodName: string,
args: QueryParameters = {},
extraOptions: Object = {}
): Promise<*> {
return this._requestAsync(
methodName,
{
httpMethod: 'get',
queryParameters: args,
json: true,
},
extraOptions
);
}
async postAsync(methodName: string, data: Object = {}, extraOptions: Object = {}): Promise<*> {
return this._requestAsync(
methodName,
{
httpMethod: 'post',
body: data,
},
extraOptions
);
}
async putAsync(methodName: string, data: Object = {}, extraOptions: Object = {}): Promise<*> {
return this._requestAsync(
methodName,
{
httpMethod: 'put',
body: data,
},
extraOptions
);
}
async _requestAsync(
methodName: string,
options: RequestOptions,
extraRequestOptions: Object
): Promise<*> {
const url = `${API_BASE_URL}/${methodName}`;
let reqOptions: Object = {
url,
method: options.httpMethod,
headers: {
'Exponent-Client': 'xdl',
},
json: typeof options.json !== 'undefined' ? options.json : false,
};
if (this.idToken) {
reqOptions.headers['Authorization'] = `Bearer ${this.idToken}`;
}
if (this.accessToken) {
reqOptions.headers['Exp-Access-Token'] = this.accessToken;
}
// Handle qs
if (options.queryParameters) {
reqOptions.params = options.queryParameters;
reqOptions.paramsSerializer = QueryString.stringify;
}
// Handle body
if (options.body) {
reqOptions.data = options.body;
}
reqOptions = _.merge({}, reqOptions, extraRequestOptions);
let response;
let result;
try {
response = await axios.request(reqOptions);
result = response.data;
} catch (e) {
// axios errors on 400's, pass this case to better error handling downstream
const maybeErrorData = idx(e, _ => _.response.data.errors.length);
if (maybeErrorData) {
result = e.response.data;
} else {
const error: ErrorWithResponseBody = new Error(
`There was a problem understanding the server. Please try again.`
);
error.responseBody = result;
logger.error(error);
throw error;
}
}
if (!result || typeof result !== 'object') {
let error: ErrorWithResponseBody = new Error(`There was a problem understanding the server.`);
error.responseBody = result;
throw error;
}
if (result.errors && result.errors.length) {
let responseError = result.errors[0];
let error = new ApiV2Error(responseError.message, responseError.code);
error.serverStack = responseError.stack;
error.details = responseError.details;
throw error;
}
return result.data;
}
}