Blazingly fast caching utility utilizing Redis - including Express Middleware

栏目: IT技术 · 发布时间: 4年前

内容简介:Simple and light NodeJS caching tool utilizing Redis for Express or indeed any other application which does not utilize such a framework.If this is of use to you, please consider starringWorried about utilzing a database for effectively every request and m

Cachi

Simple and light NodeJS caching tool utilizing Redis for Express or indeed any other application which does not utilize such a framework.

If this is of use to you, please consider starring :star2: on GitHub :grinning: .

Redis Failure

Worried about utilzing a database for effectively every request and may return errors? Not to worry, whilst Cachi will stillfor the server to handle, no errors will be returned to the client and instead the next middleware will be invoked - meaning the only bad side effect will be no cached results - only fresh ones you'll have to compute.

Why would I ever cache anything?

Well, often some requests have quite intensive processes (e.g database lookups or certain other heavy operations) to end up with a result. With caching such a request, the end result will typically be returned to the client with a significant performance increase (often reducing server load significantly, too) as only one very quick operation (to the Redis key) must be executed.

Installation

Installing Cachi is easy to install into an existing project with NPM (or indeed Yarn):

With NPM:

npm install --save cachi

With Yarn:

yarn add cachi

Express Example

const express = require("express"),
  app = express(),
  Cachi = require("cachi"),
  cachi = new Cachi("redis://localhost/0");

//Most simple example:

app.get("/", cachi.check("base"), async (req, res) => {
  //Create the result
  let result = { success: true };
  //Expiry in 1 hour (3600 seconds)
  await cachi.set("base", result, 3600); //Save the result to be cached
  //Return the result
  return res.status(200).json(result);
});

//With status codes:

app.get("/status", cachi.check("status"), async (req, res) => {
  //The result that to be cached
  let result = { weird: Date.now() * 9999 };
  await cachi.set("status", result, 3600); //Save the result to be cached
  return res.status(200).json(result); //Return the result
});

//This example will only return the cached result if certain
//aspects of the request are the same (in this case the ID URL param)

app.get(
  "/:id",
  cachi.check("id", { req: { params: ["id"] } }),
  async (req, res) => {
    let result = { id: req.params.id, weird: Date.now() * 9999 };
    await cachi.set("id", result, 3600, {
      req: { params: { id: req.params.id } },
    });
    return res.status(200).json(result);
  }
);

app.listen(3000, () =>
  console.log(`Example app listening at http://localhost:3000`)
);

Reference

Constructor

Returns:Void

Express Middleware Specific: No

new Cachi(redis = "redis://127.0.0.1/0", opts = {})

Parameters:

redis : String or Object Either the Redis database connection URI, connection object ( {host: host, port: port, password: password} ) or an ioredis instance.

opts : Object Various associated options to do with how Cachi works. There's only one key being used at the moment:

  • keyName : String What string should prefix all redis keys? Defaults to cache if not set.

.set()

Returns:Promise

Express Middleware Specific: No

cachi.set(name, data, expiry = 3600, criteria = null)

Parameters:

name : Required String What should this current result be saved as? (typically endpoint name)

data : Required Object or String What is the returned result to be saved? If using the Express middleware method, passing a string into such will cause the result to be returned to the client via the .send method. However, if it's an object, passing an object into such will cause the result to be returned to the client via the .json method

expiry : Integer How long until this result is discarded? In seconds.

criteria : What requirements must be met for this result to be returned (e.g the request body must have a certain value). IMPORTANT: If intended use of such is with express values from the request, see the.

.get()

Returns:Promise

Express Middleware Specific: No

cachi.get(name = null, criteria = null)

Parameters:

name : Required String What result should Cachi try and find to be returned?

criteria : What requirements must be met for a specific result to be returned (e.g the request body must have a certain value). IMPORTANT: If intended use of such is with express values from the request, see the.

.check()

This is effectively the same as .get() except you must call it as an Express middleware function and the name is now optional.

Returns:Promise

Express Middleware Specific: Yes

cachi.get(name, criteria = null)

Parameters:

name : String What result should Cachi try and find to be returned? (typically endpoint name). If not set, the name will be computed by adding the request's baseUrl and path strings together.

criteria : What requirements must be met for a specific result to be returned (e.g the request body must have a certain value). IMPORTANT: If intended use of such is with express values from the request, see the.

Events

As mentioned before, Cachi will not break your whole application if the Redis keystore cannot be reached (or other issues). Instead, it will emit events for you to handle.

There's only two events:

  • error : Upon an error being encountered, such will be emitted along with the error.

  • connected : Upon connecting to the Redis database, such will be emitted. Note: If you've passed an existing ioredis instance here and has already been connected, it may be unlikely for this event to be emitted for obvious reasons.

error

You can catch these errors by adding a listener for these events:

cachi.on("error", (err) => {
  console.error("Oh no! An error occured", err);
});

connected

You can be notified when the Redis keystore has been connected to adding a listener for these events:

cachi.on("connected", () => {
  console.log("Cachi has connected to Redis successfully");
});

Express "criteria" solution

So, many responses may need a certain criteria to be met based on certain request aspects for the same endpoint.

For example, let's say we had the endpoint /:id - whilst every request being made here is technically the same endpoint, the cached response should be specific to the query param - in this case id meaning that only if this value is the same in the cached store will it return the same result. Another example - /books shouldn't return the same as /prices just because it's within the same defined endpoint.

Now that we've got that out of the way, it's time to discuss how you can use certain request parameters provided by Express.

You're more than welcome to define these criterias by directly referencing the values in such an object:

let criteria = {
  name: "Edward",
};

However, some values perhaps cannot be accessed in the current scope (when defining a middleware function for example). Take this example:

app.get("/:id", cachi.check("base", { id: req.params.id }), (req, res) => {
  return res.status(200).json(result);
});

Sadly, you may not be able to access these variables in the current scope - in this case the req object.

Solution

We've devised something that should fix the issue.

As our middleware can access these variables, you can leave the key names you want the criteria to be filled with.

And it must be done like so:

cachi.check("base", { req: { params: ["id"] })

You must make these requirements within the req key. The names within such should be obvious e.g params is obviously referring to the req.params . Next to such is an array - as you may not have access to the direct variable req.params you can leave an array with all the keys you'd like to create a criteria upon.

You can do the same with the request body and with multiple keys, as mentioned above. Take this example:

cachi.check("base", { req: { body: ["page", "team"], params: ["id"] } });

This will make sure that the response generated by the page and team values within the request body and the id value within the URL parameter will only be returned when all these values match.

This also must be done in a similar form when setting

Hopefully within the main block of the route, you are able to access the req values. If not, you can still use the same format above .

For those that can:

await cachi.set("id", result, 3600, { req: { params: { id: req.params.id } } });

So it maches the other format, except actually explicitly referencing the variable as it is defined in the current scope.

This would only need to be done if it will be checked in the same format/manner. If when checked/set you are able to access these variables, don't worry about our format - do as you please.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

我是90后,我是创业家

我是90后,我是创业家

腾讯互联网与社会研究院 / 华章图书 / 2015-1-1 / 48.00元

第1本揭秘17个90后精彩创业故事 他们是:脸萌创始人郭列、北大硕士卖米粉的张天一、微博《我只过1%的生活》短时间转发35万多次的伟大的安妮、备受争议的90后总裁余佳文、节操姐CEO陈桦……17位90后的创业家为你分享他们的创业故事!从这些90后孩子的经历中,还可以看到互联网带来的巨大好处,这又是这一代人的幸运。这些创业者有一个共同特点,即他们在做自己事业的时候,会经常遇到来自家庭和社会的阻......一起来看看 《我是90后,我是创业家》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具