monobank-api-client
Version:
Monobank API client wrapper build on promises
185 lines (160 loc) • 5.15 kB
JavaScript
;
const axios = require('axios');
const assert = require('assert');
const Endpoint = require('./Endpoint');
const Signer = require('./Signer');
const MonobankBaseApi = require('./MonobankBaseApi');
const Permission = require('./Permission');
const { BAD_REQUEST, FORBIDDEN, OK, NOT_FOUND, UNAUTHORIZED } = require('./HttpStatusCode');
const AccessInfo = require('./Dto/AccessInfo');
const {
InvalidPermissionValueError,
InvalidRequestParamsError,
AccessForbiddenError,
NotFoundError,
UnauthorizedRequestError,
UndefinedApiError,
} = require('./Error');
class MonobankCorporateApi extends MonobankBaseApi {
/**
* @param {string} keyId
* @param {Signer} signer
* @param {string} baseURL
* @param {int} timeout
*/
constructor({ keyId, signer, baseURL, timeout }) {
super({ baseURL, timeout });
assert(signer instanceof Signer);
this._signer = signer;
this._client = axios.create(
Object.assign(this._clientOptions, {
headers: {
'X-Key-Id': keyId,
},
}),
);
}
/**
* @param {Permission[]} permissions
* @param {string=} callback
* @return {Promise<AccessInfo>}
*
* @throws InvalidRequestParamsError
* @throws AccessForbiddenError
* @throws UndefinedApiError
*/
async getAccessRequest({ permissions, callback = '' }) {
try {
permissions.forEach(p => assert(p instanceof Permission));
} catch (err) {
throw new InvalidPermissionValueError('Every permission in list must be instance of Permission', { permissions });
}
const permissionsStr = permissions.join('');
const endpoint = Endpoint.PERSONAL_AUTH_REQUEST;
const time = Math.floor(new Date().getTime() / 1000) + '';
const headers = {
'X-Time': time,
'X-Permissions': permissionsStr,
'X-Sign': this._signer.sign(time + permissionsStr + endpoint),
};
if (callback) {
headers['X-Callback'] = callback;
}
try {
const { data } = await this._callEndpoint({
method: 'POST',
endpoint,
headers,
});
return new AccessInfo(data);
} catch (err) {
if (err.isAxiosError) {
const { status, data } = err.response;
switch (status) {
case BAD_REQUEST:
throw new InvalidRequestParamsError(data.errorDescription || 'Invalid request');
case FORBIDDEN:
throw new AccessForbiddenError(data.errorDescription || 'Access forbidden');
default:
throw new UndefinedApiError(data.errorDescription || 'Unclassified API error');
}
}
throw new UndefinedApiError('Something went wrong');
}
}
/**
* @param {string} requestId
* @return {Promise<boolean>}
*
* @throws InvalidRequestParamsError
* @throws UnauthorizedRequestError
* @throws AccessForbiddenError
* @throws NotFoundError
* @throws UndefinedApiError
*/
async checkAccessRequest({ requestId }) {
const endpoint = Endpoint.PERSONAL_AUTH_REQUEST;
try {
const { status } = await this._callEndpoint({
method: 'GET',
endpoint,
headers: this._getAuthHeaders({ requestId, endpoint }),
});
return status === OK;
} catch (err) {
if (err.isAxiosError) {
const { status, data } = err.response;
switch (status) {
case UNAUTHORIZED:
// handle this one just as business logic response of API
return false;
case BAD_REQUEST:
throw new InvalidRequestParamsError(data.errorDescription || 'Invalid request');
case FORBIDDEN:
throw new AccessForbiddenError(data.errorDescription || 'Access forbidden');
case NOT_FOUND:
throw new NotFoundError(data.errorDescription || 'RequestId not found');
default:
throw new UndefinedApiError(data.errorDescription || 'Unclassified API error');
}
}
throw new UndefinedApiError('Something went wrong');
}
}
/**
* @param {string} requestId
* @return {Promise<UserInfo>}
*/
async getUserInfoWithRequestId(requestId) {
return super.getUserInfo(this._getAuthHeaders({ requestId, endpoint: Endpoint.CLIENT_INFO }));
}
/**
* @param {string} account
* @param {Date} from
* @param {Date=} to
* @param {string} requestId
* @return {Promise<Transaction[]>}
*/
async getStatementWithRequestId({ account, from, to }, requestId) {
to = to || new Date();
return super.getStatement(
{ account, from, to },
this._getAuthHeaders({ requestId, endpoint: this._buildStatementEndpoint(account, from, to) }),
);
}
/**
* @param {string} requestId
* @param {string} endpoint
* @return {{"X-Request-Id": *, "X-Sign": string, "X-Time": string}}
* @private
*/
_getAuthHeaders({ requestId, endpoint }) {
const time = Math.floor(new Date().getTime() / 1000) + '';
return {
'X-Time': time,
'X-Request-Id': requestId,
'X-Sign': this._signer.sign(time + requestId + endpoint),
};
}
}
module.exports = MonobankCorporateApi;