{"id":15695951,"url":"https://github.com/evanshortiss/express-expeditious","last_synced_at":"2025-09-24T00:09:10.673Z","repository":{"id":9757809,"uuid":"62590294","full_name":"evanshortiss/express-expeditious","owner":"evanshortiss","description":"flexible caching middleware for express endpoints","archived":false,"fork":false,"pushed_at":"2023-12-06T14:09:21.000Z","size":1438,"stargazers_count":52,"open_issues_count":7,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-06T11:53:02.313Z","etag":null,"topics":["cache","cache-middleware","caching","express","express-middleware","expressjs","http","middleware","nodejs","typescript"],"latest_commit_sha":null,"homepage":"","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/evanshortiss.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-04T22:08:39.000Z","updated_at":"2025-06-25T16:07:02.000Z","dependencies_parsed_at":"2024-06-18T18:36:35.423Z","dependency_job_id":null,"html_url":"https://github.com/evanshortiss/express-expeditious","commit_stats":{"total_commits":73,"total_committers":5,"mean_commits":14.6,"dds":0.452054794520548,"last_synced_commit":"32eb2e27f30bc2dcc66c4cdeed875b4395a3b27c"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/evanshortiss/express-expeditious","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanshortiss%2Fexpress-expeditious","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanshortiss%2Fexpress-expeditious/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanshortiss%2Fexpress-expeditious/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanshortiss%2Fexpress-expeditious/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evanshortiss","download_url":"https://codeload.github.com/evanshortiss/express-expeditious/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanshortiss%2Fexpress-expeditious/sbom","scorecard":{"id":385749,"data":{"date":"2025-08-11","repo":{"name":"github.com/evanshortiss/express-expeditious","commit":"32eb2e27f30bc2dcc66c4cdeed875b4395a3b27c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T16:34:28.810Z","repository_id":9757809,"created_at":"2025-08-18T16:34:28.810Z","updated_at":"2025-08-18T16:34:28.810Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276668875,"owners_count":25683158,"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","status":"online","status_checked_at":"2025-09-23T02:00:09.130Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","cache-middleware","caching","express","express-middleware","expressjs","http","middleware","nodejs","typescript"],"created_at":"2024-10-03T19:05:34.143Z","updated_at":"2025-09-24T00:09:10.639Z","avatar_url":"https://github.com/evanshortiss.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"express-expeditious\n===================\n![https://travis-ci.org/evanshortiss/express-expeditious](https://travis-ci.org/evanshortiss/express-expeditious.svg) [![npm version](https://badge.fury.io/js/express-expeditious.svg)](https://badge.fury.io/js/express-expeditious) [![https://coveralls.io/repos/github/evanshortiss/express-expeditious](https://coveralls.io/repos/github/evanshortiss/express-expeditious/badge.svg?branch=master)](https://coveralls.io/github/evanshortiss/express-expeditious?branch=master)\n[![TypeScript](https://badges.frapsoft.com/typescript/version/typescript-next.svg?v=101)](https://github.com/ellerbrock/typescript-badges/) [![Greenkeeper badge](https://badges.greenkeeper.io/evanshortiss/express-expeditious.svg)](https://greenkeeper.io/)\n\nAn express middleware that simplifies caching responses for HTTP requests of any\ntype. It also handles many unique cases such as piping data, using sessions, and\nETags. This middleware is implemented at the socket level, so it is entirely\ntransparent to the response methods such as `res.json`, `res.end`, etc. and\nstays out of your way as a result. TypeScript support is also included.\n\n\n## How Does it Work?\n\nUsing the default settings it works by:\n\n1. Generating a cache key for all incoming GET requests\n2. Checking if that key already exists in a storage engine\n3. Responding with the cached data if found, otherwise process the request using\nthe defined router logic and place the response in the cache if the status code\nwas a HTTP 200 (success).\n\n\n## Features\n\n* Support for TypeScript.\n* Seamlessly caches responses without the need to modify route handler code.\n* Caches all response functions and data types, e.g `res.json`, `res.sendFile`,\n`res.pipe`, etc.\n* Cache storage engines can be swapped easily. You're not limited to node.js\nmemory or redis (but there are adapters prebuilt for those two).\n* Is `express-session` (`req.session`) aware. This ensures user data is not\naccidentally shared when two users request the same URL.\n* Retains ETag (HTTP 304) support from express 4.12.X and for all response types\nincluding those piped or of file format.\n* Support for custom cache key generation.\n* Can override caching behaviours using a custom function.\n* Cache times can be configured on a per status code basis.\n* Cache inspection and invalidation using the underlying `expeditious` instance\n* Support for `timestring` format for setting cache timeouts. For example you\ncan pass `'1 hour'` instead of `60 * 60 * 1000`.\n* Responses contain an `x-expeditious-cache` header that states either `hit` or\n`miss` so clients can determine if the data is a cached copy.\n\n\n## Install\n\n```\nnpm install express-expeditious --save\n```\n\nYou can also install one of these to customise the cache storage location:\n\n* expeditious-engine-redis\n* expeditious-engine-memory (this is the default)\n\nIf you'd like to write an engine of your own for another storage system then take a look at the source\ncode for those modules - it's pretty easy and there's more information [here](https://github.com/evanshortiss/expeditious#custom-engines).\n\n## Usage\nThese examples will cache any successful request - this is a request that you\nsend a 200 status code to the client.\n\n\n### Using the Default In-Memory Cache\n```js\nconst getExpeditiousCache = require('express-expeditious');\nconst express = require('express');\n\nconst cache = getExpeditiousCache({\n  // Namespace used to prevent cache conflicts, must be alphanumeric\n  namespace: 'expresscache',\n\n  // Store cache entries for 1 minute (can also pass milliseconds e.g 60000)\n  defaultTtl: '1 minute'\n});\n\nconst app = express();\n\n// the initial call to this will take 2 seconds, but any subsequent calls\n// will receive a response instantly from cache for the next hour\napp.get('/ping', cache.withTtl('1 hour'), (req, res) =\u003e {\n  setTimeout(() =\u003e {\n    res.end('pong');\n  }, 2000);\n});\n\n// Cache everything below this line for 1 minute (defaultTtl)\napp.use(cache);\n```\n\n### Using the Default In-Memory Cache with TypeScript\nSimilar to the regular JavaScript example:\n\n```ts\nimport * as expeditious from 'express-expeditious';\nimport * as express from 'express';\n\nconst cacheoptions: expeditious.ExpeditiousOptions = {\n  namespace: 'expresscache',\n  defaultTtl: '1 minute'\n};\n\nconst cache = expeditious(cacheoptions);\n\nconst app = express();\n\n// the initial call to this will take 2 seconds, but any subsequent calls\n// will receive a response instantly from cache for the next hour\napp.get('/ping', cache.withTtl('1 hour'), (req, res) =\u003e {\n  setTimeout(() =\u003e {\n    res.end('pong');\n  }, 2000);\n});\n```\n\nThere's also a TypeScript sample folder in this repo at `/example-ts`.\n\n\n### Using Redis\nJust like before, except we pass a redis engine:\n\n```js\nconst getExpeditiousCache = require('express-expeditious');\nconst express = require('express');\n\nconst cache = getExpeditiousCache({\n  namespace: 'expresscache',\n  defaultTtl: '1 minute',\n  engine: require('expeditious-engine-redis')({\n    // options for the redis driver\n    host: 'redis.acme.com',\n    port: 6379\n  })\n});\n\nconst app = express();\n\napp.use(cache);\n\napp.get('/ping', (req, res) =\u003e {\n  setTimeout(() =\u003e {\n    res.end('pong');\n  }, 2000);\n});\n```\n\n### Cache Storage Format\nCurrently cached data is stored in the following format:\n\n```js\n\n{\n  headers: String\n  data: {\n    type: 'Buffer',\n    data: Uint8Array\n  }\n}\n```\n\nFor example, here's a cache entry that would be stored by the module:\n\n```js\n{\n  \"headers\": \"HTTP/1.1 200 OK\\r\\nX-Powered-By: Express\\r\\nx-expeditious-cache: hit\\r\\nDate: Thu, 14 Jun 2018 16:16:33 GMT\\r\\nConnection: close\\r\\nTransfer-Encoding: chunked\",\n  \"data\": {\n    \"type\": \"Buffer\",\n    \"data\": [\n      13,\n      10,\n      13,\n      10,\n      49,\n      13,\n      10,\n      111,\n      13,\n      10,\n      49,\n      13,\n      10,\n      107,\n      13,\n      10,\n      48,\n      13,\n      10,\n      13,\n      10\n    ]\n  }\n}\n```\n\nThis format could be changed to improve the ability to query for specific\nheaders or data. The use of Buffers is to ensure binary/compressed data can be\ncached, but PRs and ideas surrounding this are welcome. For example, we could\nstore non-binary data as strings to simplify the ability to query it.\n\n### Using Modifers\nYou can modify cache behaviour for specific endpoint or routers easily like so:\n\n```js\nconst app = require('express')();\nconst isEmpty = require('lodash.isempty');\nconst products = require('lib/products');\nconst cache = require('express-expeditious')({\n  namespace: 'expresscache',\n  defaultTtl: '1 minute'\n});\n\n\n/**\n * Exposes a /products endpoint that can be queried for a list of products.\n *\n * If the client provides a querystring then the request will NOT be cached.\n *\n * The endpoint is also session independent meaning the data returned is the\n * same regardless of the user that calls, so we set sessionAware to false since\n * it will reduce resource usage.\n */\napp.get(\n  '/products',\n\n  cache\n    .withSessionAwareness(false)\n    .withCondition((req) =\u003e { return isEmpty(req.query) }),\n\n  (req, res, next) =\u003e {\n    products.list(req.query)\n      .then((listOfProducts) =\u003e res.json(listOfProducts))\n      .catch(next)\n  }\n);\n\n\n/**\n * Expose a /orders endpoint that caches all HTTP 200 responses for 5 minutes.\n * It overrides the default behaviour and also caches 404 responses for a given\n * request for 1 minute - by default only 200 responses are cached\n */\napp.use(\n  '/orders',\n\n  cache\n    .withTtl('5 minutes')\n    .withTtlForStatus('1 minute', 404),\n\n  require('lib/routes/orders')\n);\n```\n\n## Debugging\nIf you need to enable logging for this module, simply run your application in a\nsession with a DEBUG environment variable set to \"express-expeditious\" like so:\n\n```\nexport DEBUG=express-expeditious\n$ node your-app.js\n```\n\nThis will have *express-expeditious* to enable the\n[debug](https://www.npmjs.com/package/debug) logger module it uses.\n\n\n## Benchmarks\nHere's the performance increase seen in simple benchmarks using Apache Bench.\nAll of these tests use `expeditious-engine-memory` for storage meaning the\nnode.js process memory is used.\n\nYou can run the same tests using the following commands:\n\n```\n# after cloning the repo\ncd express-expeditious/\nnpm install\nnpm run benchmark-server\n```\n\nYou need to run MongoDB locally on its default port of 27017 also. These tests\nwere performed with MongoDB running inside docker using the following command:\n\n\n```\ndocker run --name mongodb -p 27017:27017 -p 28017:28017 -d mongo\n```\n\nNow, to start the tests run the command below in another terminal:\n\n```\nab -n 1000 -c 100 http://localhost:8080/$ENDPOINT_TO_TEST\n```\n\nHere are the requests per second averaged from 4 runs:\n\n![](https://raw.githubusercontent.com/evanshortiss/express-expeditious/master/benchmark/requests-per-second.png)\n\nAnd here is the average time taken for each request averaged over 4 runs:\n\n![](https://raw.githubusercontent.com/evanshortiss/express-expeditious/master/benchmark/time-per-request.png)\n\nIt's clear that with caching applied using *express-expeditious* latency is\nreduced so your application will feel more responsive and the amount of requests\nper second that can be served increases significantly.\n\n\n## Full Example\nSee the example folder [here](https://github.com/evanshortiss/express-expeditious/tree/master/example).\n\nYou can hit HTTP endpoints on the example server using the following URLs:\n\n* http://localhost:8080/ - Uses `res.render` to render a homepage\n* http://localhost:8080/ping - Uses `res.end`\n* http://localhost:8080/sendfile - Uses `res.sendFile`\n* http://localhost:8080/pipe - Uses `res.pipe`\n* http://localhost:8080/write - Uses `res.write`\n\nAll of these URLs respond after 2 seconds on the first call, but subsequent\ncalls will use *express-expeditious* to respond instantly using the cache.\n\n\n## API\nThis module is a factory function (similar to express) that returns a\nmiddleware function. A number of options are supported and are explained in the\nfollowing sections.\n\n### module(opts)\nCreate a middleware `instance` using _opts_. Supported options are:\n\n* [Optional] expeditious - The expeditious instance that will be used for caching response data for requests.\n* [Optional] shouldCache - Function that will be called to determine if the response for a request should be cached.\n* [Optional] genCacheKey - Function that will be called to generate a custom key for reading and writing a response\n* [Optional] sessionAware - Determines if the default cache key generation will\ninclude the session token in the key. Defaults to true since this is the safest\noption to prevent data leaks between users. If `genCacheKey` is also supplied\nthen this option is ignored.\nfrom the cache. By default _req.originalUrl_ is used as the key.\n* [Optional] statusCodeExpires - Useful if you want different status code responses to be cached for different\ndurations.\n* [Optional] cacheStatusHeader - Default responses use `x-expeditious-cache` as the header key. Set a new string value to \ncustomize the header or `false` if you prefer not to write the expeditious response header.\n* [Required/Optional] defaultTtl - This is required if the `expeditious` option is not passed. Represents time entries\nwill remain in the cache. Can be set to any value the `timestring` module accepts.\n* [Required/Optional] namespace - This is required if the `expeditious` option is not passed. It's used as a namespace\nto prevent cache conflicts.\n* [Required/Optional] engine - This is required if the `expeditious` option is not passed. It is the storage engine for\ncaching.\n\nThese options are covered in greater detail in the behaviours section below.\n\n### instance.withTtl(number)\nReturns a new cache middleware that has a `defaultTtl` setting of `number`, but\ninherits other values of the parent instance.\n\n```js\nconst cache = require('express-expeditious')({\n  namespace: 'mycache',\n  defaultTtl: '30 minutes'\n});\n\nconst userRoutes = require('./routes/users');\n\n// Set cache time (defaultTtl) for /users to 15 minutes\napp.use('/users', cache.withTtl('15 minutes'), userRoutes);\n```\n\n### instance.withNamespace(string)\nCreates a new cache instance with the given namespace. All other settings are\ninherited from the parent instance.\n\n### instance.withTtlForStatus(ttl, statusCode)\nCreates a new cache instance with the given ttl for a specific status code.\nAll other settings are inherited from the parent instance. Previously supplied\nvalues for `statusCodeExpires` will be used, but the values you pass to this\nfunction will override if a conflict in values is found.\n\n### instance.withCondition(function)\nReturns a new cache middleware that has a `shouldCache` setting of its parent\noverwritten by the passed function. Passing nothing will create an instance\nwithout a `shouldCache` entry. Other settings are inherited.\n\n### instance.withCacheKey(function)\nReturns a new cache middleware that has a `genCacheKey` setting of its parent\noverwritten by the passed function. Passing nothing will create an instance\nwithout a `genCacheKey` entry. Other settings are inherited.\n\n### instance.withSessionAwareness([boolean])\nReturns a new cache instance that either respects or ignores sessions. Pass\n_true_ to create a clone of the original instance, but ignore sessions. Passing\n_false_ will create an instance that will include session IDs in generated cache\nkeys. Passing no arguments is treated the same as passing _true_.\n\nNOTE: If you supply a `genCacheKey` or `withCacheKey` option then this option\nwill not apply since you have chosen to generate cache keys manually.\n\n### instance.flush([string, ]callback)\nDeletes all cache entries associated with this middleware namespace and fires\nthe callback once complete. If you supply a _string_ for the first parameter\nthis will be passed to the flush function to target specific keys.\n\n\n## Behaviours\n\n### When to use the Cache (_shouldCache_ or _withCondition_)\n\n#### Default\nBy default only HTTP GET requests with 200 responses are cached using the URL\nas the primary unique identifier (key). The querystring is included in this\nidentifier meaning _GET /users?name=john_ and _GET /users?name=jane_ are both\ncached separately and only if a 200 response is received.\n\n#### Custom\nIf the default behaviour is undesirable that's fine, simply provide a\n_shouldCache_ function in the options to *express-expeditious* and you can have\nany logic you desire to determine if a request should be cached.\n\n```js\nconst cache = expressExpeditious({\n  defaultTtl: 30000,\n  namespace: 'mycache',\n\n  shouldCache: function (req) {\n    // by default this middleware will cache all successful PUT requests\n    return 'put' === req.method.toLowerCase();\n  }\n});\n\nconst cacheWhenNoSessionExists = cache.withCondition((req, res) =\u003e {\n  // if req.session is not found then the middleware will cache this request\n  return req.hasOwnProperty('session') === false;\n});\n```\n\nYou can also use the _statusCodeExpires_ (see Status Code Variations below)\nto determine if you would like to cache a non 200 response.\n\n\n### Cache Key Generation (_genCacheKey_ or _withCacheKey_)\n\n#### Default\nThe default cache key is generated using:\n\n* req.method\n* req.session.id (if you are using `express-session`)\n* req.originalUrl\n\nHere's a sample cache key from an application or route that's using\n`express-session`:\n\n```\nGET-fa0391d0a99ca3693bb8d658feabd28b-/cached\n```\n\nAnd here's one not using `express-session`:\n\n```\nGET-/cached\n```\n\n#### Custom\nYou can define custom a custom key for incoming requests by providing a\n_genCacheKey_ option when creating _express-expeditious_ instances.\n\nHere's an example for an API that has versioning based on a header:\n\n```js\nconst cache = expressExpeditious({\n  defaultTtl: 30000,\n  namespace: 'mycache',\n\n  // cache key is based on a session id, api version, method, and url\n  genCacheKey: function (req, res) {\n    const sessionId = req.session.id;\n    const version = req.headers['x-api-version'];\n    const resource = req.originalUrl;\n    const method = req.method;\n\n    // Could also use res to access etag etc.\n    return `${method}-${resource}-${version}-${sessionId}`;\n  }\n});\n\n// this is similar to the default key generation in this middleware, but is\n// simply provided for the sake of an example here - there's no need to do this\nconst versionlessCache = cache.withCacheKey((req, res) =\u003e {\n  const sessionId = req.session.id;\n  const resource = req.originalUrl;\n  const method = req.method;\n\n  return `${method}-${resource}-${sessionId}`;\n});\n```\n\n### Hit/Miss Header (_cacheStatusHeader_)\n\n#### Default\nAn `x-expeditious-cache` header is returned in each response with the value of\n`hit` or `miss` to indicate if the request was served by the cache.\n\n#### Custom\nPassing the `cacheStatusHeader` option can change the name of the header from\n`x-expeditious-cache` to a value of your choosing by passing a string. You can\nalso pass the boolean value `false` to disable the header entirely.\n\n```js\nconst cache = expressExpeditious({\n  defaultTtl: '1 hour',\n  namespace: 'mycache',\n\n  // Disable sending the header\n  cacheStatusHeader: false\n})\n\nconst cache = expressExpeditious({\n  defaultTtl: '1 minute',\n  namespace: 'my-other-cache',\n\n  // Change the header name\n  cacheStatusHeader: 'x-cache-status'\n})\n```\n\n\n### Status Code Variations (_statusCodeExpires_ or _withTtlForStatus_)\n\n#### Default\nThe default behaviour for _express-expeditious_ is to cache responses that have\na status code of 200. All other status codes will not be cached.\n\n#### Custom\nTo cache non 200 responses and have different cache timeout (ttl) values for\ndifferent status codes, simply add the _statusCodeExpires_ option, and specify\nthe ttl value you would like to use for a particular status code in\nmilliseconds or as a `timestring` compatible value.\n\nAn example is provided below:\n\n```js\nconst cache = expressExpeditious({\n  defaultTtl: '1 hour',\n  namespace: 'mycache',\n\n  // 500 errors will be cached for 60 seconds, and 404s will be cached for 5\n  // minutes. 200 responses are cached for 1 hour due to defaultTtl\n  statusCodeExpires: {\n    404: '5 minutes',\n    500: 60 * 1000 // 1 minute in milliseconds\n  }\n});\n\napp.get('/users', (req, res) =\u003e {\n  res.json({\n    message: `You want a list of all users? We should implement that feature... `\n  });\n})\n\napp.get('/users/:id', cache.withTtlForStatus('10 minutes', 400), (req, res) =\u003e {\n  if (req.params.id.match(/^[0-9]+$/)) {\n    // This response will be cached for an 10 minutes due to being a 400 status\n    res.status(400).json({\n      message: 'Hmm, that ID is invalid., IDs should have numbers only.'\n    })\n  } else {\n    // This will be cached for an hour since it's a 200 response\n    res.json({\n      message: `You wanted user with ID ${req.params.id}. We should implement that feature... `\n    });\n  }\n})\n```\n\n\n## CHANGELOG\n[Click here](https://github.com/evanshortiss/express-expeditious/blob/master/CHANGELOG.md) to see the CHANGELOG.md file.\n\n\n## Contributing\nContributions are welcome and encouraged. Ensure you add or remove tests as\nneeded, and verify the build is passing for your Pull Request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevanshortiss%2Fexpress-expeditious","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevanshortiss%2Fexpress-expeditious","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevanshortiss%2Fexpress-expeditious/lists"}