npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

express-accelerate

v1.0.0

Published

An express interface module for caching and formatting responses.

Downloads

1

Readme

Logo

Accelerate

Accelerate is a NodeJS module made to interface with ExpressJS to offer a library of utilities to help develop web applications faster and more intuitively. View the API reference to sift through each of the features that exist in the library.

Application Logging

Accelerate's logging offers a rich, but light-weight set of features that will help power your express application. The idea is to create multiple instances of a logger for various parts of your application. For example, an SQL logger for SQL errors, warnings, and information, a Web logger for logging ExpressJS messages, and a cache logger for logging cache related details. Each logger can be configured with a varied set of rules and write intervals to help manage how the logger behaves.

For starters, you can create a logger like so:

const accelerate = require("express-accelerate");
const MainLogger = new accelerate.LoggerInstance({
    root: __dirname,
    file: "./logs/report.log",
    header: "MAIN"
});

Each logging instance needs a root path given to it as well as the directory and file name of where the log contents are stored. The header is what appears in the front of the log message dictating where/what the log is. In this case, the header is MAIN.

You can write to the logger easily enough:

MainLogger.write("info", "This is an information level message.");
// Prints: [MAIN][INFO][09/17/2018 12:45:32PM] : This is an information level message.

There are 5 logging levels that can be used in order of severity: error, warn, info, debug, verbose.

They all have a defined color which can be modified by going to the module folder: node_modules/express-accelerate/lib/logger.js and changing the globalColors values to fit your needs. This is a temporary solution to changing the colors of each log level since colors globally modifies the string instance. In future releases you will see that globalColors will exist in the config and are not globally attached to the string object.

LoggerInstance Configuration

Below is the default configuration JSON object for the LoggerInstance class.

{
    file: "report.log",         // File location + name.
    root: null,                 // Root directory to be used.
    header: "MAIN",             // Header to appear in front of logs.
    bufferInterval: 1000,       // Duration between each file write.,
    rules: {                    // Dictates if certain levels get added to the file.
        verbose: false,
        debug: false,
        info: true,
        warn: true,
        error: true
    }
}

If you choose to modify the rules propert in the configuration, ensure you define all of the rules in the child object. In future releases this will be changed. This is due to the implementation only checking the top layer of keys and does not check in child-layers.

LoggerInstance.write() Optional Configuration

Below is the default configuration JSON object for the write method in a LoggerInstance class.

{
    append: true,           // Determines if this particular log gets added to the log file.
    forceBuffer: false,     // Consumes the buffer immediately after writing.
    silent: false           // Does not show in app-console.
}

Application Caching

Accelerate offers in-application memory caching. This is perfect for low-medium scale web application projects that don't consume much memory over long term use. So long as your application does not dynamically add to the cache, then this will work perfect for you. For more data intensive applications, it is best to use your own caching module or service or know the bounds that your application can exist in.

Accelerate's application cache uses timers to determine when data should set to be garbage collected. Any time a user implements a new cache object, it will be given a default lifetime of 2 minutes or a user-supplied lifetime (a UNIX timestamp of a future time, recommending the use of MomentJS as a means of creating this timestamp).

The cache is checked in a set interval, by default is every 1 second (1000ms) which can be modified by passing in a configuration to the CacheInterface constructor (see below). This can be lowered rather reliably without casting too much overhead on performance. The use of javascript intervals allow the application to sit idle between each call. The cache is only checked when objects are present in the cache.

Creating a cache interface is relatively simple:

const accelerate = require("express-accelerate");
const CacheInterface = new accelerate.CacheInterface({
    checkInterval: 200 // Checks the cache every 200ms.
});

This will create an interface that allows you to add to the cache. The cache is stored as a global object and thus creating multiple interfaces access the same location in memory. Adding to the cache is super simple as well:

const moment = require("moment");

// Using MomentJS
CacheInterface.set("mykey", {my: "data"}, {
    lifetime: moment().add(30, "seconds").unix() // Lasts for 30 seconds
});

// Creating a timestamp using javascript date
CacheInterface.set("another", {foo: "bar"}, {
    lifetime: Math.round((new Date()).getTime() / 1000) + 30 // Lasts for 30 seconds
});

Getting from the cache is by far the easiest part of this entire process. This will reliably return null or data depending on whether the key exists or if the data exists/expired.

let data = CacheInterface.get("mykey"); // Returns contents of mykey if it isn't expired.
let data2 = CacheInterface.get("nothing"); // Wasn't added to the cache, most likely returns null.

Data Retrieval with Routines

At it's fundamental use, routines are superflous, but when used correctly can offer a level of abstraction that can most certainly improve the layout of your Express application routes. Typically speaking, routines are simply functions that retrieve data that are stored as key/value pairs. You can invoke a routine by providing a key and the routine handler class will fetch it for you.

The real power lies in the abstraction mechanisms of providing keys--if you had a route with variable parameters such as an API interface your path may look like this: /data/sales/:when. By defining all the available/possible route paths such as /data/sales/day or /data/sales/week as the keys to the routine, then you can pass in that to the retrieve function of the routine handler and it will fetch & run the routine to get the data. In the event that it does not find the route (because the user requested a bad route or it was not defined), you can easily send a 404 or 500 response. This takes out the tedious nature of writing if statements and completely gunking up your Express routing with huge logic.

You can start by defining a routine like this:

const accelerate = require("express-accelerate");
const sql = require("some-sql-database-module");
const RoutineHandler = new accelerate.RoutineHandler();
const CacheHandler = new accelerate.CacheHandler();

// Callback must be added as the function parameter.
// You must fill each endpoint by invoking the callback properly.
RoutineHandler.create("/data/sales/day", (callback) => {

    // Retrieve from the cache first.
    let data = CacheHandler.get("/data/sales/day");

    // If the cache found data send the data back, if not get the data and send it back.
    if (data) callback(null, data); // callback(error, data) standard
    else {

        sql.query("SELECT * FROM SALES_DATA", (error, rows) => {

            if (error) callback(error, null);
            else {

                callback(null, rows); // Send the data back through the callback.
                CacheHandler.set("/data/sales/day"); // Set the cache data.

            }

        });

    }

});

// Condensed.
RoutineHandler.create("/data/sales/week", (callback) => {
    let data = CacheHandler.get("/data/sales/week");
    if (data) callback(null, data);
    else {
        sql.query("SELECT * FROM SALES_DATA", (error, rows) => {
            if (error) callback(error, null);
            else {
                callback(null, rows);
                CacheHandler.set("/data/sales/week");
            }
        });
    }
});

Which in affect can be invoked from an Express route like so:


app.get("/data/sales/:time", (request, response) => {

    let time = request.params.time;
    RoutineHandler.retrieve("/data/sales/"+time, (error, data) => {

        // If an error, send a 404 and then log the error.
        if (error) {
            response.send(404);
            console.log(error);
        } else {
            response.send(data); // Send the data to the user.
        }

    });

});

As you can see, you wouldn't necessarily attempt to invoke a routine strictly by it's name, you would want to use a variable path name as a means of retrieving from a group of routines that are defined. If the client decides to tamper with the front-end request code, the routine handler will send an error through the callback thus allowing you to send a 404 response.