\/\/Our old API call\r\nApiService.getAll('subject-types').then(function(response) {\r\n scope.subjectTypes = response.data;\r\n});<\/pre>\nAnd now we call it with an extra parameter.<\/p>\n
\/\/Our new API call\r\nApiService.getAll('subject-types', true).then(function(response) {\r\n scope.subjectTypes = response.data;\r\n});<\/pre>\nthe true<\/code> passed into the method tells the method that this API call needs to be cached. This is what the getAll<\/code> method looks like in the APIService<\/code>.<\/p>\n\/**\r\n * \r\n * @param {[type]} routeprefix - API url\r\n * @param {[type]} cacheit - Wether this API needs to be cached or not\r\n * @param {[type]} urlsthatwillaffectthisget - the APIs that will effect the state of the cached data of this API\r\n * \r\n *\/\r\n function getAll(routeprefix, cacheit, urlsthatwillaffectthisget) {\r\n var url = '\/api\/' + routeprefix;\r\n if (cacheit) {\r\n apicache.register(url, urlsthatwillaffectthisget);\r\n }\r\n var cacheddata = apicache.get(url);\r\n if (cacheddata) {\r\n if(window.debug){\r\n console.info(\"data from cache\", url);\r\n }\r\n return new Promise(function(resolve, reject) {\r\n resolve({\r\n \"data\": cacheddata\r\n });\r\n });\r\n } else {\r\n return $http({\r\n method: 'GET',\r\n url: '\/api\/' + routeprefix\r\n });\r\n }\r\n }<\/pre>\nAs you can see in the code, I am checking if the\u00a0API needs to be cached, if yes then registering a listener for it.<\/p>\n
Whatever goes inside cache may change in the server when we add, update or delete a\u00a0record. In that case we may have to delete the cached information so that we can get the new value. To make that happen we need to identify the API calls that effect the stored value, this is where our third parameter\u00a0urlsthatwillaffectthisget<\/code> comes into picture. Take a look at the code below.<\/p>\nvar urlthataffecthisgetroute = ['students\/{{id}}\/academics\/{{id}}','students\/{{id}}\/academic'];\/\/one save and one put\r\n\r\nApiService.getAll('students\/' + studentId + '\/academics\/' + studentAcademicId, true, urlthataffecthisgetroute)\r\n.then(function(response) {\r\n scope.academic = response.data;\r\n);\r\n<\/pre>\nWe do not know what will be the exact PUT or DELETE urls, so we simply provide the url signature with UUIDs as {{id}}. So a match of this URL call will automatically delete the stored key from the client storage. If there is no third parameter then its assumed that there is no other API change affecting this value, so it will not change throughout the user session.<\/p>\n
The full caching module code is as below.<\/p>\n
\/**\r\n * API Response Caching System\r\n * This module creates a global variable called 'apicache' and makes it available throughout.\r\n *\/\r\n(function() {\r\n\r\n \/**\r\n * \r\n * Variables to store our XMLHttpRequest object methods\r\n *\/\r\n var open = window.XMLHttpRequest.prototype.open,\r\n send = window.XMLHttpRequest.prototype.send,\r\n onReadyStateChange;\r\n\r\n \/**\r\n * The prefix helps in keeping our keys unique making sure it doesn't conflict with the other keys\r\n *\/\r\n var _keyprefix = \"_storagekey_\";\r\n\r\n \/**\r\n * The regex to replace all my UUIDs to some other more easily storable format\r\n *\/\r\n var uuid_regex = \/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/g;\r\n\r\n \/**\r\n * XMLHttpRequest object\r\n *\/\r\n var xmlhttp = window.XMLHttpRequest;\r\n\r\n var url;\r\n\r\n \/**\r\n * Method that overrides our XMLHttpRequest open method\r\n * \r\n * @param String method GET,POST,PUT,DELETE etc\r\n * @param String url API url\r\n * @param String async sync or async\r\n *\/\r\n function openReplacement(method, url, async) {\r\n var syncMode = async !== false ? 'async' : 'sync';\r\n this.url = url;\r\n return open.apply(this, arguments);\r\n }\r\n\r\n \/**\r\n * Method that overrides our XMLHttpRequest send method\r\n * \r\n * @param Object data object passed as payload\r\n * \r\n *\/\r\n function sendReplacement(data) {\r\n \/\/console.log('Sending HTTP request data : ', data);\r\n\r\n if (this.onreadystatechange) {\r\n this._onreadystatechange = this.onreadystatechange;\r\n }\r\n this.onreadystatechange = onReadyStateChangeReplacement;\r\n return send.apply(this, arguments);\r\n }\r\n\r\n \/**\r\n * Method thats called when the response is recived from the server\r\n *\/\r\n function onReadyStateChangeReplacement() {\r\n \/\/console.log('HTTP request ready state changed : ' + this.readyState);\r\n \/\/console.log(this.responseText);\r\n if (this.status == 200) {\r\n \/\/store only if the route returns success\r\n storeIntoCache(this.url, this.responseText);\r\n }\r\n if (this._onreadystatechange) {\r\n return this._onreadystatechange.apply(this, arguments);\r\n }\r\n }\r\n\r\n \/**\r\n * Store data into cache. url as key and responseText as value\r\n *\/\r\n function storeIntoCache(url, responseText) {\r\n if (urlRegisteredForCache(url)) {\r\n sessionStorage.setItem(_keyprefix + url, responseText);\r\n }\r\n }\r\n\r\n \/**\r\n * Get From Cache using the URL as key. \r\n *\/\r\n function getFromCache(url) {\r\n return JSON.parse(sessionStorage.getItem(_keyprefix + url));\r\n }\r\n\r\n function urlRegisteredForCache(url) {\r\n var getroutes_tocache = JSON.parse(sessionStorage.getItem('getroutes_tocache'))\r\n if (getroutes_tocache && getroutes_tocache.indexOf(url) > -1) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n function dataCachedInStorage(url) {\r\n return sessionStorage.getItem(_keyprefix + url);\r\n }\r\n\r\n \/\/Overriding\r\n window.XMLHttpRequest.prototype.open = openReplacement;\r\n window.XMLHttpRequest.prototype.send = sendReplacement;\r\n\r\n function getstoredgetroutes() {\r\n return JSON.parse(sessionStorage.getItem('getroutes_tocache'));\r\n }\r\n\r\n \/\/We create our Cache class \r\n function Apicache() {\r\n\r\n }\r\n\r\n \/\/get data from cache\r\n Apicache.prototype.get = function(url) {\r\n return JSON.parse(sessionStorage.getItem(_keyprefix + url));\r\n }\r\n\r\n \/\/delete data from cache\r\n function remove(geturl) {\r\n sessionStorage.removeItem(_keyprefix + geturl);\r\n if (window.debug) {\r\n console.info(\"data removed from cache\" + geturl);\r\n }\r\n }\r\n\r\n \/**\r\n * check If This Route Affects Any Cached Data\r\n *\/\r\n Apicache.prototype.checkIfThisRouteAffectsAnyCachedData = function(url) {\r\n url = url.replace(uuid_regex, \"{{id}}\");\r\n var urlsthatwillaffectthisget_tocache = JSON.parse(sessionStorage.getItem('urlsthatwillaffectthisget'));\r\n if (urlsthatwillaffectthisget_tocache && urlsthatwillaffectthisget_tocache[url]) {\r\n urlsthatwillaffectthisget_tocache[url].forEach(function(geturl) {\r\n remove(geturl);\r\n });\r\n }\r\n }\r\n\r\n \/**\r\n * Register the passed url for caching. Registering basically means \r\n * I will make sure the API response for this URL is cached\r\n *\/\r\n Apicache.prototype.register = function(geturl, urlsthatwillaffectthisget) {\r\n var getroutes_tocache = JSON.parse(sessionStorage.getItem('getroutes_tocache'));\r\n if (!getroutes_tocache) {\r\n getroutes_tocache = []; \/\/create a fresh variable\r\n }\r\n if (getroutes_tocache.indexOf(geturl) == -1) {\r\n getroutes_tocache.push(geturl);\r\n }\r\n var urlsthatwillaffectthisget_tocache = JSON.parse(sessionStorage.getItem('urlsthatwillaffectthisget'));\r\n if (!urlsthatwillaffectthisget_tocache) {\r\n urlsthatwillaffectthisget_tocache = {}; \/\/create a fresh variable\r\n }\r\n if (urlsthatwillaffectthisget) {\r\n urlsthatwillaffectthisget.forEach(function(uwa) {\r\n var uwa = uwa.replace(uuid_regex, \"{{id}}\");\r\n if (!urlsthatwillaffectthisget_tocache[uwa]) {\r\n urlsthatwillaffectthisget_tocache[uwa] = [];\r\n }\r\n urlsthatwillaffectthisget_tocache[uwa].push(geturl);\r\n });\r\n sessionStorage.setItem('urlsthatwillaffectthisget', JSON.stringify(urlsthatwillaffectthisget_tocache));\r\n }\r\n sessionStorage.setItem('getroutes_tocache', JSON.stringify(getroutes_tocache));\r\n }\r\n\r\n \/\/A top level global instance where all the public ojects will be attached\r\n var apicache = new Apicache();\r\n\r\n \/\/ Attach the instance to window to make it globally available\r\n window.apicache = apicache;\r\n\r\n})();<\/pre>\n <\/p>\n","protected":false},"excerpt":{"rendered":"
Talk about caching and we talk about how we are going to\u00a0put everything into redis or memcache on our servers and send back cached responses to our\u00a0clients and make our applications respond\u00a0faster by taking the load off the databases. Below is a flow of how a typical caching\u00a0mechanism\u00a0looks like. While server caching is a phenomenal […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[52],"_links":{"self":[{"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/posts\/200"}],"collection":[{"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/comments?post=200"}],"version-history":[{"count":1,"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/posts\/200\/revisions"}],"predecessor-version":[{"id":1651,"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/posts\/200\/revisions\/1651"}],"wp:attachment":[{"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/media?parent=200"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/categories?post=200"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/write.muthu.co\/wp-json\/wp\/v2\/tags?post=200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}