UNPKG

@qikdev/sdk

Version:

Promise based Javascript SDK

512 lines (374 loc) 21.2 kB
<!DOCTYPE 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' &amp;&amp; value != null &amp;&amp; !Array.isArray(value) &amp;&amp; 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&amp;h=50&amp;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}&amp;${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 &amp;&amp; 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 &lt; 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 &lt; 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>