Skip to content

@jaypie/express

Prerequisites: npm install jaypie or npm install @jaypie/express

@jaypie/express provides Express handler wrappers with lifecycle management, automatic error formatting, and response handling.

Terminal window
npm install jaypie
# or
npm install @jaypie/express
Export Purpose
expressHandler Standard request handler wrapper
expressStreamHandler SSE/streaming handler wrapper
cors CORS middleware
createExpressStream SSE stream helper
Return Value HTTP Status
object 200
null / undefined 204
true 201
false 204
Thrown error Error status
import { expressHandler } from "jaypie";
export default expressHandler(async (req, res) => {
return { data: "result" };
});
// Returns: 200 { data: "result" }
import { expressHandler, NotFoundError } from "jaypie";
export default expressHandler(
async (req, res) => {
const user = await db.users.findById(req.params.id);
if (!user) throw NotFoundError();
return { data: user };
},
{
name: "getUser",
secrets: ["MONGODB_URI"],
validate: [(req) => req.params.id],
setup: [async () => await connectDb()],
teardown: [async () => await disconnectDb()],
}
);
Option Type Description
name string Handler name for logging
secrets string[] Secrets to load from AWS Secrets Manager
validate Function[] Validation functions (throw or return false to reject)
setup Function[] Setup functions (run before handler)
teardown Function[] Teardown functions (always run)
unavailable boolean Return 503 immediately
throw boolean Re-throw errors instead of formatting
expressHandler(handler, {
validate: [
// Return false for 400 Bad Request
(req) => req.body.email,
// Throw specific error
(req) => {
if (!req.headers.authorization) {
throw UnauthorizedError();
}
},
],
});

Share data between lifecycle functions:

expressHandler(
async (req, res) => {
// Access data from setup
return { user: req.locals.user };
},
{
setup: [
async (req) => {
req.locals.user = await loadUser(req.headers.authorization);
},
],
}
);

For Server-Sent Events (SSE) responses:

import { expressStreamHandler, createExpressStream } from "jaypie";
export default expressStreamHandler(async (req, res, context) => {
const stream = createExpressStream(context);
stream.write("Starting...\n");
for (const item of items) {
await processItem(item);
stream.write(`Processed: ${item.id}\n`);
}
stream.end();
});
import { expressStreamHandler, createExpressStream } from "jaypie";
import Llm from "@jaypie/llm";
export default expressStreamHandler(async (req, res, context) => {
const stream = createExpressStream(context);
for await (const chunk of Llm.stream(req.body.prompt)) {
stream.write(chunk.content || "");
}
stream.end();
});

CORS middleware with environment-based configuration.

import express from "express";
import { cors } from "jaypie";
const app = express();
app.use(cors());
app.use(cors({
origin: ["https://example.com", "https://app.example.com"],
credentials: true,
}));

Set allowed origins via environment variable:

Terminal window
CORS_ORIGIN=https://example.com,https://app.example.com
app.use(cors());
// Reads from CORS_ORIGIN automatically

Jaypie handlers automatically add response headers:

Header Value
X-Powered-By Removed
X-Project-Key PROJECT_KEY env var
X-Project-Env PROJECT_ENV env var
X-Invocation Unique invocation ID
import {
badRequestRoute,
forbiddenRoute,
goneRoute,
internalRoute,
notFoundRoute,
teapotRoute,
unavailableRoute,
} from "@jaypie/express";
// Returns 404 Not Found
router.get("/missing", notFoundRoute);
// Returns 503 Service Unavailable
router.get("/maintenance", unavailableRoute);
import { describe, expect, it, vi } from "vitest";
vi.mock("jaypie", async () => {
const testkit = await import("@jaypie/testkit/mock");
return testkit;
});
import myRoute from "./myRoute.js";
describe("My Route", () => {
it("returns data", async () => {
const req = { params: { id: "123" } };
const res = {};
const result = await myRoute(req, res);
expect(result).toHaveProperty("data");
});
it("throws NotFoundError for missing resource", async () => {
const req = { params: { id: "invalid" } };
await expect(myRoute(req, {})).rejects.toThrowNotFoundError();
});
});
routers/v1.router.ts
import { Router } from "express";
import usersRoute from "../routes/users.route.js";
import healthRoute from "../routes/health.route.js";
const router = Router();
router.get("/health", healthRoute);
router.get("/users/:id", usersRoute);
export default router;
app.ts
import express from "express";
import { cors } from "jaypie";
import v1Router from "./routers/v1.router.js";
const app = express();
app.use(cors());
app.use(express.json());
app.use("/v1", v1Router);
export default app;