@qikdev/sdk
Version:
Promise based Javascript SDK
512 lines (374 loc) • 21.2 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>qik.api.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
<div class="navicon"></div>
</label>
<label for="nav-trigger" class="overlay"></label>
<nav >
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="access.html">access</a><ul class='methods'><li data-type='method'><a href="access.html#.actionableScopes">actionableScopes</a></li><li data-type='method'><a href="access.html#.allPermissions">allPermissions</a></li><li data-type='method'><a href="access.html#.allPermissionTypes">allPermissionTypes</a></li><li data-type='method'><a href="access.html#.allUserScopes">allUserScopes</a></li><li data-type='method'><a href="access.html#.canCreate">canCreate</a></li><li data-type='method'><a href="access.html#.canDeleteItem">canDeleteItem</a></li><li data-type='method'><a href="access.html#.canEditItem">canEditItem</a></li><li data-type='method'><a href="access.html#.canEraseItem">canEraseItem</a></li><li data-type='method'><a href="access.html#.canKnowOf">canKnowOf</a></li><li data-type='method'><a href="access.html#.canListItem">canListItem</a></li><li data-type='method'><a href="access.html#.canRestoreItem">canRestoreItem</a></li><li data-type='method'><a href="access.html#.canViewItem">canViewItem</a></li><li data-type='method'><a href="access.html#.checkActionAccess">checkActionAccess</a></li><li data-type='method'><a href="access.html#.getAllDescendants">getAllDescendants</a></li><li data-type='method'><a href="access.html#.has">has</a></li><li data-type='method'><a href="access.html#.hashPermissions">hashPermissions</a></li><li data-type='method'><a href="access.html#.isAdministrator">isAdministrator</a></li><li data-type='method'><a href="access.html#.isOwner">isOwner</a></li></ul></li><li><a href="api.html">api</a><ul class='methods'><li data-type='method'><a href="api.html#.delete">delete</a></li><li data-type='method'><a href="api.html#.generateEndpointURL">generateEndpointURL</a></li><li data-type='method'><a href="api.html#.get">get</a></li><li data-type='method'><a href="api.html#.patch">patch</a></li><li data-type='method'><a href="api.html#.post">post</a></li><li data-type='method'><a href="api.html#.put">put</a></li></ul></li><li><a href="auth.html">auth</a><ul class='methods'><li data-type='method'><a href="auth.html#.changeOrganisation">changeOrganisation</a></li><li data-type='method'><a href="auth.html#.ensureValidToken">ensureValidToken</a></li><li data-type='method'><a href="auth.html#.getCurrentToken">getCurrentToken</a></li><li data-type='method'><a href="auth.html#.getCurrentUser">getCurrentUser</a></li><li data-type='method'><a href="auth.html#.impersonate">impersonate</a></li><li data-type='method'><a href="auth.html#.login">login</a></li><li data-type='method'><a href="auth.html#.logout">logout</a></li><li data-type='method'><a href="auth.html#.retrieveUserFromResetToken">retrieveUserFromResetToken</a></li><li data-type='method'><a href="auth.html#.sendResetPasswordRequest">sendResetPasswordRequest</a></li><li data-type='method'><a href="auth.html#.set">set</a></li><li data-type='method'><a href="auth.html#.sync">sync</a></li><li data-type='method'><a href="auth.html#.updateUserWithToken">updateUserWithToken</a></li></ul></li><li><a href="cache.html">cache</a><ul class='methods'><li data-type='method'><a href="cache.html#.get">get</a></li><li data-type='method'><a href="cache.html#.reset">reset</a></li></ul></li><li><a href="content.html">content</a><ul class='methods'><li data-type='method'><a href="content.html#.create">create</a></li><li data-type='method'><a href="content.html#.delete">delete</a></li><li data-type='method'><a href="content.html#.get">get</a></li><li data-type='method'><a href="content.html#.getFromSlug">getFromSlug</a></li><li data-type='method'><a href="content.html#.glossary">glossary</a></li><li data-type='method'><a href="content.html#.list">list</a></li><li data-type='method'><a href="content.html#.patch">patch</a></li><li data-type='method'><a href="content.html#.restore">restore</a></li><li data-type='method'><a href="content.html#.scopeGlossary">scopeGlossary</a></li><li data-type='method'><a href="content.html#.update">update</a></li><li data-type='method'><a href="content.html#.validateField">validateField</a></li><li data-type='method'><a href="content.html#.variables">variables</a></li></ul></li><li><a href="files.html">files</a><ul class='methods'><li data-type='method'><a href="files.html#.downloadUrl">downloadUrl</a></li><li data-type='method'><a href="files.html#.filesize">filesize</a></li><li data-type='method'><a href="files.html#.getBinaryTypeFromMime">getBinaryTypeFromMime</a></li><li data-type='method'><a href="files.html#.mediaUrl">mediaUrl</a></li></ul></li><li><a href="filter.html">filter</a><ul class='methods'><li data-type='method'><a href="filter.html#.activeFilterKeys">activeFilterKeys</a></li><li data-type='method'><a href="filter.html#.activeFilterKeys">activeFilterKeys</a></li><li data-type='method'><a href="filter.html#.activeFilterOperators">activeFilterOperators</a></li><li data-type='method'><a href="filter.html#.activeFilters">activeFilters</a></li><li data-type='method'><a href="filter.html#.activeFilterValues">activeFilterValues</a></li><li data-type='method'><a href="filter.html#.filterChangeString">filterChangeString</a></li><li data-type='method'><a href="filter.html#.isValidFilter">isValidFilter</a></li></ul></li><li><a href="socket.html">socket</a><ul class='methods'><li data-type='method'><a href="socket.html#.channel">channel</a></li><li data-type='method'><a href="socket.html#.close">close</a></li><li data-type='method'><a href="socket.html#.connect">connect</a></li><li data-type='method'><a href="socket.html#.reconnect">reconnect</a></li><li data-type='method'><a href="socket.html#.subscribe">subscribe</a></li><li data-type='method'><a href="socket.html#.unsubscribe">unsubscribe</a></li></ul></li><li><a href="system.html">system</a><ul class='methods'><li data-type='method'><a href="system.html#.countries">countries</a></li></ul></li></ul>
</nav>
<div id="main">
<h1 class="page-title">qik.api.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>import axios from 'axios';
import qs from 'qs';
import { version } from '../version.js';
import {
cacheAdapterEnhancer,
throttleAdapterEnhancer,
Cache,
} from 'axios-extensions';
function isString(value) {
const type = typeof value
return type === 'string' || (type === 'object' && value != null && !Array.isArray(value) && getTag(value) == '[object String]')
}
/**
* Creates a new instance of Axios, with automatic authentication and token refreshing functionality.
* This module provides all the underlying functions for making http requests and interacting with the REST API.
* It is a wrapper around the axios library, a popular promise based javascript request package. The api module is used by most other modules in the SDK and will handle authentication, token refreshing and other headers automatically.
* @alias api
* @constructor
* @hideconstructor
* @param {QikAPI} qik A reference to the parent instance of the QikCore module. This module is usually created by a QikCore instance that passes itself in as the first argument.
*/
const CancelToken = axios.CancelToken;
///////////////////////////////////////
var QikAPI = function(qik) {
var defaultCache;
if (typeof window !== 'undefined') {
defaultCache = qik.cache.get('api');
}
const defaultAdapter = axios.defaults.adapter
/////////////////////////////////////////////////////
function getRequestCacheKey(config) {
var key = [
config.method,
config.url,
config.headers?.Authorization,
config.headers.Accept,
JSON.stringify({
params: config.params,
data: config.data,
}),
].filter(Boolean).join('-')
return key;
}
///////////////////////////////////////
const inflightRequests = {};
let cacheAdapter = function(config) {
var cacheKey = getRequestCacheKey(config);
// If there is already an identical request being made
if (!inflightRequests[cacheKey]) {
// Be more efficient and wait for the existing request
inflightRequests[cacheKey] = new Promise(function(resolve, reject) {
var useCache;
var cachedResponse;
///////////////////////////////////////
switch (String(config.method).toLowerCase()) {
case 'post':
case 'patch':
case 'put':
case 'delete':
//Unless we've specified we want a cache
if (!config.cache) {
//Don't use the cache
config.cache = false;
}
break;
}
///////////////////////////////////////
if (config.cache === false) {
//No cache so make new request
} else {
//Use the cache specified or the default cache
useCache = config.cache || defaultCache;
//If there is a cache
if (useCache) {
//If we have the cachedResponse version
cachedResponse = useCache.get(cacheKey);
}
}
///////////////////////////////////////
if (cachedResponse) {
return resolve(cachedResponse);
}
var copy = Object.assign(config, { adapter: defaultAdapter });
return axios.request(config)
.then(function(res) {
delete inflightRequests[cacheKey];
resolve(res);
}, function(err) {
delete inflightRequests[cacheKey];
reject(err);
});
})
}
return inflightRequests[cacheKey];
}
//////////////////////////////////////////////////////////////////////////////
const service = createNewAxios(cacheAdapter);
//////////////////////////////////////////////////////////////////////////////
/**
*
* Generate an Endpoint URL, complete with authentication.
* this function is helpful for generating authenticated links for the user to open in another window
* @alias api.generateEndpointURL
* @param {String} endpoint The endpoint to generate a url for
* @param {Object} params Extra parameters for the url
* @param {Object} options Additional request configuration
* @param {Object} options.withoutToken Don't append the current user's access token to the url
* @param {Object} options.file Whether the response for this request is expected to be a binary file type
* @example
*
*
* const result = sdk.api.generateEndpointURL('/image/61eca4746971e75c1fc670cf', {
* w:100,
* h:50,
* }, {file:true})
*
* // Would return something similar to:
* // https://api.qik.dev/image/61eca4746971e75c1fc670cf?w=100&h=50&access_token=XXXX...
*/
service.generateEndpointURL = function(endpoint, params, options) {
options = options || {}
params = params || {};
var token;
const apiURL = options.file ? qik.fileAPI || qik.apiURL : qik.apiURL;
//Append the access token to the url
if (!options.withoutToken) {
delete params.access_token;
token = qik.auth.getCurrentToken();
}
var stripLeadingTag = endpoint[0] == '/' ? endpoint.slice(1) : endpoint;
var parameterString = qik.utils.mapParameters(params);
if (token) {
parameterString = parameterString ? `?access_token=${token}&${parameterString}` : `?access_token=${token}`;
} else {
parameterString = parameterString ? `?${parameterString}` : '';
}
var url = `${apiURL}${endpoint}${parameterString}`
return url;
}
//////////////////////////////////////////////////////////////////////////////
service.wasCancelled = function(err) {
return axios.isCancel(err);
}
//////////////////////////////////////////////////////////////////////////////
/**
*
* Make a GET request to the API
* @alias api.get
* @param {Object} endpoint The endpoint to request
* @param {Object} options The options to pass to axios for making the request
* @example
*
* const result = await sdk.api.get('/user');
*/
var f = function() {}
/**
*
*
* @alias api.post
* @description Make a POST request to the API
* @param {Object} endpoint The endpoint to request
* @param {Object} body The post body to send with the request
* @param {Object} options The options to pass to axios for making the request
* @example
*
* const result = await sdk.api.post('/login', {username:'', password:''});
*/
var f = function() {}
/**
*
* Make a PUT request to the API
* @alias api.put
* @param {Object} endpoint The endpoint to request
* @param {Object} body The post body to send with the request
* @param {Object} options The options to pass to axios for making the request
* @example
*
* const result = await sdk.api.put('/content/61eca4746971e75c1fc670cf', {title:'A new title'});
*/
var f = function() {}
/**
*
* Make a PATCH request to the API
* @alias api.patch
* @param {Object} endpoint The endpoint to request
* @param {Object} body The post body to send with the request
* @param {Object} options The options to pass to axios for making the request
* @example
*
* const result = await sdk.api.patch('/content/61eca4746971e75c1fc670cf', {title:'A new title'});
*/
var f = function() {}
/**
*
* Make a DELETE request to the API
* @alias api.delete
* @param {Object} endpoint The endpoint to request
* @param {Object} body The post body to send with the request
* @param {Object} options The options to pass to axios for making the request
* @example
*
* const result = await sdk.api.delete('/content/61eca4746971e75c1fc670cf');
*/
var f = function() {}
function createNewAxios(adapter) {
var instance = axios.create({
paramsSerializer: params => qs.stringify(params, { arrayFormat: 'repeat' }),
adapter,
});
///////////////////////////////////////
instance.defaults.baseURL = qik.apiURL;
instance.defaults.headers.common.Accept = 'application/json';
/////////////////////////////////////////////////////
// Add relative date and timezone to every request
instance.interceptors.request.use(function(config) {
const inflightKey = getRequestCacheKey(config);
if (config.withoutToken) {
return config;
}
config.headers['qik-request-date'] = new Date().getTime();
if (Intl) {
config.headers['qik-request-timezone'] = Intl.DateTimeFormat().resolvedOptions().timeZone;
}
config.headers['qik-api-version'] = version;
// Include the socket window id in the request
if(qik?.socket?.windowID) {
config.headers['qik-socket-window'] = qik.socket.windowID;
}
var token = qik.auth.getCurrentToken();
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
if (config.params && config.params.access_token) {
delete config.params.access_token;
}
}
return config;
});
/////////////////////////////////////////////////////
let retryCount = 0;
instance.interceptors.response.use(function(response) {
var config = response.config
//Get the response status
var status = response.status;
switch (status) {
case 204:
// No content give it another try
if (retryCount < 5) {
retryCount++;
// Wait a second and try again
return new Promise(function(resolve, reject) {
setTimeout(function() {
return instance.request(config).then(resolve, reject);
}, 800);
})
} else {
console.log('Failed after 5 retries')
retryCount = 0;
}
break;
}
return response;
}, function(err) {
if (axios.isCancel(err)) {
return Promise.reject(err);
}
//Get the response status
var status = err?.response?.status || err.status;
//Check the status
switch (status) {
case 401:
//Ignore let QikAuth handle it
break;
case 502:
case 504:
if (retryCount < 5) {
retryCount++;
// Wait a second and try again
return new Promise(function(resolve, reject) {
setTimeout(function() {
return instance.request(err.config).then(resolve, reject);
}, 800);
})
} else {
console.log('Failed after 5 retries')
retryCount = 0;
}
break;
case 404:
//Not found
break;
default:
//Some other error, likely a problem connecting to the server
// console.log('qik.api > connection error', status, err);
break;
}
/////////////////////////////////////////////////////
return Promise.reject(err);
})
return instance;
}
/////////////////////////////////////////////////////
function retrieveIDs(data) {
var dataString;
if (_isString(data)) {
dataString = data;
} else {
dataString = JSON.stringify(data);
}
//Find all mongo ids included in the object
var myregexp = /[0-9a-fA-F]{24}/g;
var matches = dataString.match(myregexp);
//Make sure the matches are unique
return [...new Set(matches)];
}
///////////////////////////////////////
/**
*
* Reference to the underlying axios package (https://www.npmjs.com/package/axios)
* Useful for creating new instances of axios if you want to create http requests to
* external APIs and not send tokens etc..
* @name api.axios
* @example
* const newRequest = await sdk.api.axios.get('https://otherapi.com/content/61eca4746971e75c1fc670cf');
*/
service.CancelToken = CancelToken;
service.axios = axios;
///////////////////////////////////////
return service;
}
///////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////
export { CancelToken as CancelToken };
export default QikAPI;</code></pre>
</article>
</section>
</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Thu Sep 28 2023 07:24:39 GMT+1000 (Australian Eastern Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>
</body>
</html>