joyent-portal/packages/cloudapi-gql/src/api/request.js

109 lines
2.4 KiB
JavaScript

const { createError } = require('apollo-errors');
const awaitify = require('apr-awaitify');
const auth = require('smartdc-auth');
const cloudapi = require('triton/lib/cloudapi2');
const bunyan = require('bunyan');
const fetch = require('node-fetch');
const url = require('url');
const pkg = require('../../package.json');
const credentials = require('../credentials');
const errors = require('./errors.json');
const STATUSES = [
400,
401,
403,
404,
405,
406,
409,
413,
415,
420,
449,
500,
503
];
const ERRORS = Object.keys(errors).reduce(
(errs, code) =>
Object.assign(errs, {
[code]: createError(code, { message: errors[code] })
}),
{}
);
const log = bunyan.createLogger({
name: pkg.name
});
const client = cloudapi.createClient({
log,
url: credentials.url,
account: credentials.account,
user: credentials.user,
sign: auth.cliSigner({
log,
keyId: credentials.keyId,
user: credentials.account,
subuser: credentials.user
})
});
const { _path, _getAuthHeaders, account, url: host } = client;
const getAuthHeaders = awaitify(_getAuthHeaders.bind(client));
module.exports = (method, args) => {
return new Promise((resolve, reject) => {
const fn = client[method].bind(client);
const cb = (err, res) => {
if (err) {
return reject(err);
}
resolve(res);
};
return args ? fn(args, cb) : fn(cb);
});
};
module.exports.client = client;
module.exports.fetch = async (_pathanme, reqOpts = {}) => {
const method = (reqOpts.method || 'get').toUpperCase();
const pathname = _path.call(client, _pathanme.replace(/:login/, account));
const headers = await getAuthHeaders(method, pathname);
const href = url.format({
protocol: 'https',
host: host.replace(/^https:\/\//, ''),
pathname
});
return fetch(
href,
Object.assign(reqOpts, {
method,
headers: Object.assign({}, reqOpts.headers, headers)
})
)
.then(async response => [response.status, await response.json()])
.then(([status, body]) => {
// eslint-disable-next-line no-implicit-coercion
if (~STATUSES.indexOf(status)) {
const { code, message } = body;
const CustomError = ERRORS[code] || ERRORS.UnknownError;
throw new CustomError({
message,
data: { pathname, body: reqOpts.body }
});
}
return body;
});
};