\$\begingroup\$

I'm writing a node.js module that is basically a wrapper for some API functions of third party company.

I tried to make it flexible and easy to fill with API functions from documentation and came up with this.

Module returns an instance of the API Client that can connect to API and stay connected (so it basically works like MongoCli, except it's not a db, but I find it easy to use that way).

/** * Creates NfieldClient object * @constructor NfieldClient */ function NfieldCliConstructor (defOptions) { var defaultRequestCliOptions = { baseUrl : 'https://api.nfieldmr.com/', headers : { 'Content-Type' : 'application/json' } }; extend(true, defaultRequestCliOptions, defOptions); /** * Returns a new instance of NfieldClient with new request parameters */ this.defaults = function defaults (options) { if (typeof options !== 'object') throw new Error('`options` must be an object with request parameters'); return new NfieldCliConstructor(options); }; /** * Connects NfieldClient to API * Returns ConnectedInstance */ this.connect = function connect (credentials, callback) { if (typeof credentials === 'undefined' || typeof credentials === 'function') throw new Error('not all required parameters provided: no `credentials`'); if (!credentials.Domain || !credentials.Username || !credentials.Password) throw new Error('not all required parameters provided: no `Domain` or `Username` or `Password`'); var token = {}; var promise = SignIn(defaultRequestCliOptions, credentials).then(function (data) { if (data[0].statusCode !== 200) { throw new Error(`${data[0].statusCode}: ${data[0].body.Message}`); } else { token = { AuthenticationToken : data[0].body.AuthenticationToken, Timestamp : Date.now() }; return new ConnectedInstance(defaultRequestCliOptions, token, credentials); } }).nodeify(callback); return promise; }; } module.exports = { NfieldClient : new NfieldCliConstructor() };

The .connect function from Client returns ConnectedInstance that contains all API functions and refreshes API token if needed:

/** * Wrapper function for all Nfield API requests that checks if API token is not outdated, and refreshes it otherwise */ function requestWithTokenCheck (defOptions, credentials, token, options, callback) { var returnedPromise; var chainedPromise; extend(true, options, defOptions); chainedPromise = request(options); if (Date.now() - token.Timestamp > tokenUpdateTime) { returnedPromise = SignIn(defOptions, credentials).then(function (data) { if (data[0].statusCode !== 200) { throw new Error(`${data[0].statusCode}: ${data[0].body.Message}`); } else { token.AuthenticationToken = data[0].body.AuthenticationToken; token.Timestamp = Date.now(); return chainedPromise; } }); } else { returnedPromise = chainedPromise; } returnedPromise.nodeify(callback); return returnedPromise; } /** * Returns Nfield survey status * * {@link https://api.nfieldmr.com/help/api/get-v1-surveys-surveyid-fieldwork-status} */ function getSurveyStatus (defOptions, credentials, token, surveyId, callback) { var options = { method : 'GET', uri : `v1/Surveys/${surveyId}/Fieldwork/Status`, headers : { 'Authorization' : `Basic ${token.AuthenticationToken}` } }; return requestWithTokenCheck(defOptions, credentials, token, options, callback); } /** * Creates an instance of object, connected to Nfield API */ function ConnectedInstance (requestOptions, authToken, credentials) { this.__REQUEST_OPTIONS = requestOptions; this.__TOKEN = authToken; this.__CREDENTIALS = credentials; this.SurveyFieldwork = { status : getSurveyStatus.bind(this, this.__REQUEST_OPTIONS, this.__CREDENTIALS, this.__TOKEN), start : startSurvey.bind(this, this.__REQUEST_OPTIONS, this.__CREDENTIALS, this.__TOKEN), stop : stopSurvey.bind(this, this.__REQUEST_OPTIONS, this.__CREDENTIALS, this.__TOKEN) }; }

Full code could be found on GitHub.

There are several things that bothering me: