{"id":26268046,"url":"https://github.com/oslabs-beta/cachier","last_synced_at":"2025-04-30T19:25:35.115Z","repository":{"id":62902259,"uuid":"561909387","full_name":"oslabs-beta/Cachier","owner":"oslabs-beta","description":"Library of GraphQL caching solutions - develop \u0026 deploy with GraphQL easier \u0026 faster. 3 npm packages under the name @cachier - client \u0026 server-side custom eviction policy, cache normalization \u0026 partial query retrieval. Demo app to visualize the efficiency of our solutions is launched!","archived":false,"fork":false,"pushed_at":"2023-05-11T21:59:28.000Z","size":14794,"stargazers_count":57,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-08T10:53:13.816Z","etag":null,"topics":["cache","caching","caching-strategies","graphql","graphql-caching","node","nodejs","react","redis"],"latest_commit_sha":null,"homepage":"https://cachierql.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oslabs-beta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-11-04T19:17:10.000Z","updated_at":"2025-01-16T21:10:09.000Z","dependencies_parsed_at":"2023-02-19T01:16:15.138Z","dependency_job_id":null,"html_url":"https://github.com/oslabs-beta/Cachier","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FCachier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FCachier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FCachier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FCachier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oslabs-beta","download_url":"https://codeload.github.com/oslabs-beta/Cachier/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251768042,"owners_count":21640648,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","caching","caching-strategies","graphql","graphql-caching","node","nodejs","react","redis"],"created_at":"2025-03-14T04:19:15.082Z","updated_at":"2025-04-30T19:25:35.092Z","avatar_url":"https://github.com/oslabs-beta.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\n[![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n[![MIT License][license-shield]][license-url]\n[![LinkedIn][linkedin-shield]][linkedin-url]\n\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/oslabs-beta/Cachier\"\u003e\n    \u003cimg src=\"demo/client/styles/cachierlogo.png\" alt=\"Cachier Logo\" title=\"Cachier Logo\" width=\"520\" height=\"180\"\u003e\n  \u003c/a\u003e\n\n\u003ch3 align=\"center\"\u003eCachier\u003c/h3\u003e\n\n  \u003cp align=\"center\"\u003e\n    GraphQL caching tool with custom eviction policies, cache normalization.\n    \u003cbr /\u003e\n    \u003ca href=\"https://cachierql.com/\"\u003e\u003cstrong\u003eExplore the docs »\u003c/strong\u003e\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/oslabs-beta/Cachier\"\u003eView Demo\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/oslabs-beta/Cachier/issues\"\u003eReport Bug\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/oslabs-beta/Cachier/issues\"\u003eRequest Feature\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003c!-- TABLE OF CONTENTS --\u003e\n\u003cdetails\u003e\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\n  \u003col\u003e\n    \u003cli\u003e\n      \u003ca href=\"#about-the-project\"\u003eAbout The Project\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#built-with\"\u003eBuilt With\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n      \u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#if-using-redis\"\u003ePrerequisites\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#installation-and-import\"\u003eInstallation\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#roadmap\"\u003eRoadmap\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#license\"\u003eLicense\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#contributors\"\u003eContact\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#works-cited\"\u003eAcknowledgments\u003c/a\u003e\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n\u003c!-- ABOUT THE PROJECT --\u003e\n## About The Project\n\n### Built With\n\n [![React][React.js]][React-url]\n [![Redis][Redis.io]][Redis-url]\n [![GraphQL][GraphQL.io]][GraphQL-url]\n [![Node/Express][Express.io]][Express-url]\n [![TailwindCSS][TailwindCSS.io]][Tailwind-url]\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\nWelcome to Cachier, a lightweight GraphQL caching tool that is configured specifically for GraphQL to reduce load times and minimize data fetching.\n\nGraphQL does not have native HTTP caching as a result of its singular employment of the POST method, forcing the danger of over-fetching by re-running queries and slowing load times. Our team of engineers developed a compact, easy-to-use solution that allows users to cache their queries on the server side and client side!\n\n#### Cachier currently offers:\n- Storage inside session storage for client side caching\n- Ability to choose between Redis and a native in memory cache\n- Unique key generation for response data to avoid developer having to tag for the cache\n- Partial and exact matching for query fields in the developer's GraphQL API\n- Highly configurable eviction policies\n\n\n#### We created a highly performant and customizable GraphQL caching library that consists of three main caching functions:\n- Cachier Normalized Server-side Cache\n- Cachier Direct Server-side Cache\n- Cachier Direct Client-side Cache\n\nWe will go over each solution in detail below:\n\n\u003c!-- GETTING STARTED --\u003e\n## Getting Started\n## Cachier Normalized Server-side Cache\n\nCachier's Normalized Server-side Cache breaks up GraphQL queries into individual sub-queries to be stored in the cache. This provides maximum cache efficency by organizing data in a way that prevents data redundancy and allows for partial retrievals of subset data, thus drastically reducing network requests to the database.\n\n## Installation and Import\nIf this is your first time using Cachier's Normalized Cache, run the following command in your terminal.\n~~~\nnpm install @cachier/cache-partials\n~~~\n\nIn your server file, require our middleware to handle GraphQL requests using the CommonJS format\n~~~\nconst Cachier = require('@cachier/cache-partials');\n~~~\n\n## Set up your Cachier middleware function\nendpoint - the endpoint that the client will make GraphQL queries to if it wants to utilize the cache.\n#### graphQLEndpoint \n- The graphQLEndpoint parameter is where you will specify your GraphQL APIs endpoint. This allows Cachier to route all queries that are unable to be resolved by the Cachier Cache to your GraphQL API.\n#### cacheCapacity \n- the cacheCapacity parameter allows you to specify a maximum cache length which allows cachier to know when to evict from the cache. All inputs for Capacity will be multiples of 100. The default parameter for Capacity is 100 (1000 keys in the cache).\n#### sampleSize \n- the sampleSize parameter allows the developer to configure the number of random keys that will be considered for eviction. The default sampleSize is 5 which we recommend for most applications.\n#### evictionSize \n- the sampleSize parameter allows the developer to configure the number of evictions what will be made when your cache capacity is reached. The default evictionSize is 5.\n\n~~~\napp.use(\n       endpoint,\n       Cachier(graphQLEndPoint, cacheCapacity, sampleSize, evictionSize);\n~~~\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\u003c!-- USAGE EXAMPLES --\u003e\n\n## Usage\n\n~~~\napp.use( '/Cachier', Cachier('https://api.spacex.land/graphql', 100, 5, 5) );\n~~~\n\nTo fetch from Cachier's normalized cache you will fetch like you would to your GraphQL API except you will need set the option for uniques in the request body. The uniques object will need to contain a unique identifier for all list items in your query. You will need to include the list name as the key and the unique identifier as a the value. The unique identifier is any piece of data that is queried that is unique to each list item!\n\n~~~\nfetch('/graphql', {\n  method: 'POST',\n   headers:{\n     'Content-Type': 'application/json',\n     Accept: 'application/json',\n },\n    body: JSON.stringify({\n      query: queryGraphQLString,\n      uniques: {listKey :uniqueIdentifier},\n       })\n    });\n~~~\n\n\n### How it works \n\n\nExample Fetch to SpaceX GQL API:\n\n  ~~~\nfetch('http://localhost:3000/partialCache', {\n            method: 'POST',\n            headers: {\n              'Content-Type': 'application/json',\n              Accept: 'application/json',\n            },\n            body: JSON.stringify({\n              query: {\n                dragons {\n                  id\n                  return_payload_mass {\n                    kg\n                  }\n                }\n              }\n              ,\n              uniques: { dragons: 'id' },\n            }),\n          })\n        \n ~~~\n          \n          \nThe client will fetch to the Cachier Cache endpoint with an object containing the query string and the unique types. The unique types need contain a unique identifier for all array/list items so that Cachier can generate a unique cache key. \n\n ~~~\n{\n   \"typesArr\": [\n      \"dragons\"\n   ],\n   \"fieldsArr\": [\n      [\n         \"__typename\",\n         \"id\",\n         {\n            \"return_payload_mass\": [\n               \"__typename\",\n               \"kg\"\n            ]\n         }\n      ]\n   ]\n}\n~~~\n          \n         \n Cachier parses incoming GraphQL queries and seperates them into subqueries stored in a \"Cachier\" object. The queries are broken up into 2 arrays typesArr, and fieldsArr where their respective indexes connect with one another. FieldsArr will be an array of arrays containing the fields for each cacheKey, if a field is nested it will be stored as a nested object. We will then wait for the return Data and use this \"Cachier\" query object to sort the data into our cache.\n \n\nHere is data returned from our example query:\n~~~\n{\n  \"data\": {\n    \"dragons\": [\n      {\n        \"id\": \"dragon2\",\n        \"return_payload_mass\": {\n          \"kg\": 3000\n        }\n      },\n      {\n        \"id\": \"dragon1\",\n        \"return_payload_mass\": {\n          \"kg\": 3000\n        }\n      }\n    ]\n  }\n}\n~~~\n\nAfter receiving the data back Cachier will utilize the query map stored in the \"Cachier\" Object to normalize and store the data as individual keys inside the cache. This is how the data will look once normalized and stored in the cache:\n~~~\n{\n   \"dragons\": [\n      \"dragon:dragon2\",\n      \"dragon:dragon1\",\n      8492.694458007812\n   ],\n   \"dragon:dragon2\": {\n      \"__typename\": \"Dragon\",\n      \"id\": \"dragon2\",\n      \"return_payload_mass\": {\n         \"__typename\": \"Mass\",\n         \"kg\": 3000\n      },\n      \"__CachierCacheDate\": 8492.681999921799\n   },\n   \"dragon:dragon1\": {\n      \"__typename\": \"Dragon\",\n      \"id\": \"dragon1\",\n      \"return_payload_mass\": {\n         \"__typename\": \"Mass\",\n         \"kg\": 3000\n      },\n      \"__CachierCacheDate\": 8492.691667079926\n   }\n}\n~~~\nAs you can see the dragons array now only stores references to keys in the cache and the data from the array is stored as seperate keys unique in the cache. This normalized cache structure eliminiates data redundancy in the cache and allows for partial retrieval of subset data. (\"__CachierCacheData\" fields and the number at the last index array is to keep track of recency for our eviction policy which we will speak about next).\n\n\n### Approximated LRU Eviction \n\nCachier's Normalized Cache uses a custom Approximated LRU Eviction Policy. This is not a true LRU implementation, but it comes very close in terms of performance. The reason Cachier does not use a true LRU implementation is because it costs more memory. Cachier's LRU policy works by creating a sample (the sample size can be configured by the developer) of randomly selected keys from the cache and evicting the least recently used key from the sample.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Cachier Direct Server-side Cache\nCachier's Direct Server-side Cache uses a custom LRU-SLFR (Least Recently Used Smallest Latency First Replacement) policy. LRU-SLFR is very similar to LRU except it takes latency into account as well as recency when evicting. Cachier's LRU-SLFR eviction policy utilizes a linked hash map to achieve true LRU and allows O(1) deletion, lookup, and insertion. Cachier takes latency into account as well as recency by creating a group of least recent queries and removes the query with the lowest latency first. This allows for much smarter evictions compared to traditional LRU. The whole group will be evicted first before moving on to the next group. Check out the demo page for a visualization of the eviction policy\n\n### How to install and import\nIf this is your first time using Cachier's Direct Server-side Cache, run the following command in your terminal.\n\n~~~\nnpm install @cachier/server-side\n~~~\n\nIn your server file, require our middleware to handle GraphQL requests using the CommonJS format\n\n~~~\nconst Cachier = require('@cachier/server-side')\n~~~\n\n### Set up your Cachier middleware function\n\n#### Endpoint \n- The endpoint that the client will make GraphQL queries to if it wants to utilize the cache.\n#### graphQLEndpoint \n- The graphQLEndpoint parameter is where you will specify your GraphQL APIs endpoint. This allows Cachier to route all queries that are unable to be resolved by the Cachier Cache to your GraphQL API.\n#### capacity \n- the cacheCapacity parameter allows you to specify a maximum cache length which allows cachier to know when to evict from the cache.\n#### groupSize \n- the groupSize parameter allows the developer to configure the number of least recently used keys that will be considered for eviction. The key with the least latency out of the group will be evicted first. The whole group will be evicted first before moving on to the next group.\n#### RedisClient \n- If you would like to use Redis to store your cache, insert your connected redis client as an arguement. If you leave out this parameter Cachier will default to its native built in cache.\n\n\n~~~\napp.use(\n       endpoint,\n       Cachier(graphqlEndpoint, capacity, groupSize, RedisClient(optional));\n~~~\n\nExample implementation without Redis:\n\n~~~\napp.use( '/Cachier', Cachier('https://api.spacex.land/graphql', 100, 5) );\n~~~\n\n\n### If using Redis\nFirst, install the Redis package for Node.js\n\n`npm install redis`\n\nThen install redis npm package.\n`npm install _______`\n1. Install Redis\n- MacOS users: [Redis installation for MacOS](https://redis.io/docs/getting-started/installation/install-redis-on-mac-os/)\n- Linux users: [Redis installation for Linux](https://redis.io/docs/getting-started/installation/install-redis-on-linux/)\n- Windows users: \n1. Redis is not officially supported on Windows, so you must have a [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/install).\n2. Once you have WSL, follow [Redis installation for Windows](https://redis.io/docs/getting-started/installation/install-redis-on-windows/)\n\n\n## Cachier Direct Client-side Cache\n\nCachier's Direct Client-Side Cache uses the same underlying mechanisms as Cachier's Direct Server-side cache except it stores the cache in the client browsers session storage. This allows for even faster cached query times than a server side implementation. Cachier's client side cache was built to mimic a traditional fetch request so it is very easy to integrate into new and existing codebases.\n\n### Installation and Import\n\nIf this is your first time using Cachier's Direct Client-side Cache, run the following command in your terminal.\n\n~~~\nnpm install @cachier/client-side\n~~~\n\nIn your client file, import the cachier client side function:\n\n~~~\nimport clientSideCache from '@cachier/client-side';\n~~~\n\n### Initalize your Cachier client-side cache\n\n#### capacity \n- the cacheCapacity parameter allows you to specify a maximum cache length which allows cachier to know when to evict from the cache.\n#### groupSize \n- the groupSize parameter allows the developer to configure the number of least recently used keys that will be considered for eviction. The key with the least latency out of the group will be evicted first. The whole group will be evicted first before moving on to the next group.\n\n~~~\nconst cachierFetch = clientSideCache(500, 5);\n~~~\n\nOperates exactly like fetch():\n\n~~~\ncachierFetch('/graphql', {\n  method: 'POST',\n   headers:{\n     'Content-Type': 'application/json',\n     Accept: 'application/json',\n },\n    body: JSON.stringify({\n      query: queryGraphQLString,\n       })\n    });\n~~~\n\n\u003c!-- ROADMAP --\u003e\n## Roadmap\n\n- [ ] Mutation handling\n- [ ] Full partial querying\n- [ ] Demo with more options\n    - [ ] Faster text editor\n\nSee the [open issues](https://github.com/oslabs-beta/Cachier/issues) for a full list of proposed features (and known issues).\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003c!-- CONTRIBUTING --\u003e\n## Contributing\n\nContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\nIf you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag \"enhancement\".\nDon't forget to give the project a star! Thanks again!\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the Branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Tech stack used\nNode - Express - React - Tailwind CSS - ChartJS - Redis - GraphQL - TypeScript - Jest - Supertest - Webpack \n\n## Here's how to contribute to our open source library\nOur vision for our open-source project is for fellow developers to be able to interate on and improve this tool. This is exactly where you and the community comes in. So, if you have an idea that can make Cachier better, you can make that idea come to life by following the steps below: \n\n1. Fork Cachier\n2. Pull down our dev branch with command  ```git pull origin dev```\n3. Create your own Feature Branch with the command ```git checkout -b \u003cyourFeatureName\u003e```\n4. Add your changes with the command ```git add .```\n5. Stage and commit your changes with the command ```git commit -m \"\u003cyour comment\u003e\"```\n6. Merge your branch with the dev branch locally with the command ```git merge dev```\n7. Resolve any merge conflicts\n8. Push up your branch with the command ```git push origin \u003cyour feature branch name\u003e```\n9. Open a pull request\n\nPlease star our repo if you've found this useful, we want to be able to help as many of developers as we can!\n\n## Contributors\n* Andy Zheng || [Github](https://github.com/andy5313) || [Linkedin](https://www.linkedin.com/in/andyzheng5313/)\n* Dhruv Thota || [Github](https://github.com/L05Dhruv) || [Linkedin](https://www.linkedin.com/in/dhruv-thota/)\n* Jonathan Chen || [Github](https://github.com/jchen0903i) || [Linkedin](https://www.linkedin.com/in/jonathan-chen3/)\n* Kaju Sarkar || [Github](https://github.com/kajusarkar) || [Linkedin](https://www.linkedin.com/in/kaju-sarkar-a6329862/)\n* Roman Darker || [Github](https://github.com/romanjamesd) || [Linkedin](https://www.linkedin.com/in/roman-darker-707147175/)\n\n## Works cited\n- LRU based small latency first replacement (SLFR) algorithm for the proxy cache. (2003). Proceedings IEEE/WIC International Conference on Web Intelligence (WI 2003). https://doi.org/10.1109/wi.2003.1241250\n- Wang, Y., Yang, J., \u0026 Wang, Z. (2020). Dynamically Configuring LRU Replacement Policy in Redis. The International Symposium on Memory Systems. https://doi.org/10.1145/3422575.3422799\n- Morales, K., \u0026 Lee, B. K. (2012). Fixed Segmented LRU cache replacement scheme with selective caching. 2012 IEEE 31st International Performance Computing and Communications Conference (IPCCC). https://doi.org/10.1109/pccc.2012.6407712\n\n\n## License\nDistributed under the MIT license.\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n\u003c!-- https://www.markdownguide.org/basic-syntax/#reference-style-links --\u003e\n[contributors-shield]: https://img.shields.io/github/contributors/oslabs-beta/Cachier.svg?style=for-the-badge\n[contributors-url]: https://github.com/oslabs-beta/Cachier/graphs/contributors\n[forks-shield]: https://img.shields.io/github/forks/oslabs-beta/Cachier.svg?style=for-the-badge\n[forks-url]: https://github.com/oslabs-beta/Cachier/network/members\n[stars-shield]: https://img.shields.io/github/stars/oslabs-beta/Cachier.svg?style=for-the-badge\n[stars-url]: https://github.com/oslabs-beta/Cachier/stargazers\n[issues-shield]: https://img.shields.io/github/issues/oslabs-beta/Cachier.svg?style=for-the-badge\n[issues-url]: https://github.com/oslabs-beta/Cachier/issues\n[license-shield]: https://img.shields.io/github/license/oslabs-beta/Cachier.svg?style=for-the-badge\n[license-url]: https://github.com/oslabs-beta/Cachier/blob/master/LICENSE.txt\n[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge\u0026logo=linkedin\u0026colorB=555\n[linkedin-url]: https://linkedin.com/company/cachier\n[product-screenshot]: images/screenshot.png\n[React.js]: https://img.shields.io/badge/React-20232A?style=for-the-badge\u0026logo=react\u0026logoColor=61DAFB\n[React-url]: https://reactjs.org/\n[Redis.io]: https://img.shields.io/badge/Redis-Data%20store-red\n[Redis-url]: https://redis.io/\n[GraphQL.io]: https://img.shields.io/badge/%20-GraphQL-brightgreen\n[GraphQL-url]: https://graphql.org/learn/\n[Express.io]: https://img.shields.io/badge/Node-Express-orange\n[Express-url]: https://expressjs.com/\n[TailwindCSS.io]: https://img.shields.io/badge/%20UI-TailwindCSS%20-blue\n[Tailwind-url]: https://v2.tailwindcss.com/docs\n[Vue.js]: https://img.shields.io/badge/Vue.js-35495E?style=for-the-badge\u0026logo=vuedotjs\u0026logoColor=4FC08D\n[Vue-url]: https://vuejs.org/\n[Angular.io]: https://img.shields.io/badge/Angular-DD0031?style=for-the-badge\u0026logo=angular\u0026logoColor=white\n[Angular-url]: https://angular.io/\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foslabs-beta%2Fcachier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foslabs-beta%2Fcachier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foslabs-beta%2Fcachier/lists"}