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

@biblioteksentralen/cloud-functions-core

v0.1.5

Published

Core package for apps using Cloud Functions

Downloads

71

Readme

Core package for Cloud Functions services

This package contains some core functionality for Node.js services running on Google Cloud Run via Cloud Functions, such as logging and error handling.

Development

pnpm install
pnpm test

Publishing the package:

pnpm version patch  # or minor / major
pnpm publish

Initialization

npm install @google-cloud/functions-framework @biblioteksentralen/cloud-functions-core

To create a new Express app for Cloud Functions:

import { http } from "@google-cloud/functions-framework";
import { createApp } from "@biblioteksentralen/cloud-functions-core";
import { z } from "zod";

const projectId = z.string().parse(process.env.GCP_PROJECT_ID);
const app = createApp({ projectId });
http("my-cloud-function", app);

This configures the app with a logging middleware that configures Pino for Cloud Logging and includes trace context. The logger is added to the Express Request context, so it can be used in all request handlers like so:

app.get("/", async (req, res, next) => {
  req.log.info(`Hello log!`);
  // ...
});

The app is also registered with the Cloud Functions framework.

Tip: Formatting logs with pino-pretty in development

When developing, pino-pretty can be used to format logs in a more human readable way. Since cloud-functions-core configures Pino for Google Cloud Logging, we need to explicitly tell pino-pretty about which keys we use with the flags --messageKey and --levelKey. Here's a package.json example (remember to npm i -D pino-pretty):

{
  "scripts": {
    "dev": "functions-framework --target=fun-service --signature-type=http | pino-pretty --colorize --messageKey message --levelKey severity"
  }
}

It's also possible to create a .pino-prettyrc file if the script definition becomes too convoluted.

Error handling

This package provides an errorHandler middleware for error handling in Express 4 inspired by How to Handle Errors in Express with TypeScript. It includes the express-async-errors polyfill to support throwing errors from async request handlers, a feature that will be supported natively in Express 5.

import { http } from "@google-cloud/functions-framework";
import { createApp, errorHandler } from "@biblioteksentralen/cloud-functions-core";
import { z } from "zod";

const projectId = z.string().parse(process.env.GCP_PROJECT_ID);
const app = createApp({ projectId });
http("my-cloud-function", app);

// Define routes, middlewares, etc...
// app.get("/", defaultRequestHandler);
// ...

// Error handler should be added at the very end, after all other handlers.
app.use(errorHandler);

The package provides AppError, a base class to be used for all known application errors (that is, all errors we throw ourselves).

import {
  AppError,
  RequestHandler
} from "@biblioteksentralen/cloud-functions-core";

export const defaultRequestHandler: RequestHandler = async (req, res, next) => {
  // ...
  throw new AppError('🔥 Databasen har brent ned');
  // ...
};

As long as errors are thrown before writing the response has started, a JSON error response is produced on the form:

{ "error": "🔥 Databasen har brent ned" }

By default, errors based on AppError are considered operational and displayed in responses. If an error should not be displayed, set isOperational: false when constructing the error:

throw new AppError('🔥 Databasen har brent ned', { isOperational: false });

This results in a generic error response (but the original error is still logged):

{ "error": "Internal server error" }

A generic error response will also be shown for any unknown error, that is, any error that is not based on AppError) is thrown. All errors, both known and unknown, are logged.

By default, errors use status code 500. To use another status code:

throw new AppError('💤 Too early', { httpStauts: 425 });

The package also provides a few subclasses of AppError for common use cases, such as ClientRequestError (yields 400 response) and Unauthorized (yields 401 response).

throw new Unauthorized('🔒 Unauthorized');

Pub/Sub helpers

The package provides a helper function to parse and validate Pub/Sub messages delivered through push delivery.

The package is agnostic when it comes to which schema parsing/validation library to use. We like Zod for its usability, and have added support for it in the errorHandler, but it's not very performant (https://moltar.github.io/typescript-runtime-type-benchmarks/), so you might pick something else if performance is important (if you do, remember to throw ClientRequestError when validation fails).

import { z } from "zod";
import {
  parsePubSubMessage,
  Request,
  Response,
} from "@biblioteksentralen/cloud-functions-core";

const messageSchema = z.object({
  table: z.string(),
  key: z.number(),
});

app.post("/", async (req: Request, res: Response) => {
  const message = parsePubSubMessage(req, (data) => messageSchema.parse(JSON.parse(data)));
  // ...
});