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

@saasquatch/express-boilerplate

v1.1.0

Published

Boilerplate middleware and functions for building Express apps on Kubernetes

Downloads

79

Readme

The SaaSquatch exporess boilerplate package provides a number of middleware and utility functions that are useful in Express apps, particularly those running in Kubernetes environments.

Getting Started

Install the package:

npm install @saasquatch/express-boilerplate

Basic usage:

import {
  healthCheck,
  installShutdownManager,
  requestIdAndLogger,
  shutdownManagerConfigFromEnv,
} from "@saasquatch/express-boilerplate";

import { httpLogMiddleware, initializeLogger } from "@saasquatch/logger";
import express from "express";

const app = express();
const baseLogger = initializeLogger();

app.use(requestIdAndLogger(baseLogger));
app.use(httpLogMiddleware(baseLogger));
app.get("/healthz", healthCheck(app, baseLogger));

const server = installShutdownManager(
  app,
  baseLogger,
  shutdownManagerConfigFromEnv(),
);

server.listen(3000, () => baseLogger.notice("App listening on port 3000"));

Graceful Shutdown Manager

The installShutdownManager function installs the OS signal handlers for SIGINT and SIGTERM to shutdown the server in a graceful way that is compatible with Kubernetes best practices. It is also used to configure the TCP Keep-Alive timeouts for the server, which may be necessary for certain cloud load balancers.

The shutdownManagerConfigFromEnv() function will load the following config options from environment variables:

| Environment variable | Config option | Meaning | | -------------------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SSQT_HTTP_KEEP_ALIVE_SECONDS | keepAliveTimeoutSeconds | The number of seconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed. | | SSQT_TERMINATION_DELAY_SECONDS | terminationDelaySeconds | The number of seconds to wait after the shutdown signal is received and before exiting the application process. |

The options can also be customized directly:

const server = installShutdownManager(app, logger, {
  keepAliveTimeoutSeconds: 620,
  terminationDelaySeconds: 20,
});

server.listen(3000, () => logger.notice("App listening on port 3000"));

The shutdown manager also supports executing hook functions when certain events occur during the shutdown process:

const server = installShutdownManager(app, logger, {
  ...shutdownManagerConfigFromEnv(),

  onSignalReceived: async (signal) =>
    console.log(`"${signal}" signal received!`),

  beforeShutdown: async () => console.log(`HTTP server is about to shut down`),

  afterShutdown: async () => console.log(`HTTP Server has shut down`),
});

server.listen(3000, () => logger.notice("App listening on port 3000"));

RequestId and Logger Middleware

The requestIdAndLogger middleware function generates a random request ID using nanoid and sets the res.locals.requestId and res.locals.logger variables. These can be used in the subsequent request handlers to generate log events with the requestId automatically attached.

const baseLogger = initializeLogger();
app.use(requestIdAndLogger(baseLogger));

app.get("/testing", (req, res) => {
  const logger = res.locals.logger;
  const requestId = res.locals.requestId;

  logger.info(`The requestId is: ${requestId}`);

  // produces log event with { "requestId": "XXXXXXXXXXXX" } as a field
  logger.info("Inside the /testing request handler!");
});

Async request handler wrapper

The asyncHandlerWrapper function wraps an async request handler to automatically catch any rejected promises, log the error, and return an appropriate response. Without this function the default behavior is for unhandled promise rejections to crash the application, which is obviously unwanted.

This function requires that the requestIdAndLogger middleware function is installed.

import {
  asyncHandlerWrapper,
  requestIdAndLogger,
} from "@saasquatch/express-boilerplate";

app.use(requestIdAndLogger(baseLogger));

// BAD -- promise rejection in getSomethingFromTheDatabase will crash
// the application
app.get("/testing", async (req, res) => {
  const dbResults = await getSomethingFromTheDatabase();
  res.status(200).json(dbResults);
});

// OK -- promise rejection in getSomethingFromTheDatabase will be handled by
// the wrapper and return an appropriate 500 response
app.get(
  "/testing",
  asyncHandlerWrapper(async (req, res) => {
    const dbResults = await getSomethingFromTheDatabase();
    res.status(200).json(dbResults);
  }),
);

nanoid re-export

The library exports a nanoid function, which is just vanilla nanoid with a custom alphabet of characters that are a bit easier to read. Its default ID length is 32.

import { nanoid } from "@saasquatch/express-boilerplate";

console.log(nanoid());
console.log(nanoid(12));