用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill express-api命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
基于 SOC 职业分类
正在显示 SKILL.md
| name | express-api |
| description | >- Use when this capability is needed. |
try/catch in every route. Use an async wrapper and
a single error-handling middleware at the end of the middleware chain.helmet, configure cors explicitly (never * in
production), and apply rate limiting to public endpoints.process.env directly
throughout the codebase.{ data, error, meta }.src/
├── config/
│ └── env.ts # Validated environment config
├── middleware/
│ ├── errorHandler.ts # Centralized error handler
│ ├── validate.ts # Request validation middleware
│ ├── auth.ts # Authentication middleware
│ └── rateLimiter.ts # Rate limiting config
├── routes/
│ ├── index.ts # Route aggregator
│ └── users.routes.ts # /users route definitions
├── controllers/
│ └── users.controller.ts # HTTP concern handling
├── services/
│ └── users.service.ts # Business logic
├── repositories/
│ └── users.repository.ts # Data access
├── errors/
│ └── AppError.ts # Custom error classes
├── utils/
│ └── asyncHandler.ts # Async error wrapper
└── app.ts # Express app setup
import express from "express";
import helmet from "helmet";
import cors from "cors";
import { rateLimit } from "express-rate-limit";
import { errorHandler } from "./middleware/errorHandler";
import { routes } from "./routes";
const app = express();
// Security middleware — order matters
app.use(helmet());
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(",") ?? [],
credentials: true,
}));
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100,
standardHeaders: true,
legacyHeaders: false,
}));
// Body parsing
app.use(express.json({ limit: "10kb" }));
app.use(express.urlencoded({ : }));
app.(, routes);
app.(, {
res.({ : });
});
app.(errorHandler);
{ app };
import { Request, Response, NextFunction, RequestHandler } from "express";
// Wraps async route handlers so thrown errors reach the error middleware
export const asyncHandler = (
fn: (req: Request, res: Response, next: NextFunction) => Promise<void>
): RequestHandler => {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
};
export class AppError extends Error {
constructor(
public readonly statusCode: number,
public readonly message: string,
public readonly isOperational = true,
) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
Error.captureStackTrace(this);
}
}
export class NotFoundError extends AppError {
constructor(resource: string) {
super(404, `${resource} not found`);
}
}
export class ValidationError extends AppError {
constructor(message: string) {
super(400, message);
}
}
import { Request, Response, NextFunction } from "express";
import { AppError } from "../errors/AppError";
import { ZodError } from "zod";
export function errorHandler(
err: Error,
_req: Request,
res: Response,
_next: NextFunction,
): void {
// Zod validation errors
if (err instanceof ZodError) {
res.status(400).json({
error: "Validation failed",
details: err.errors.map((e) => ({
path: e.path.join("."),
message: e.message,
})),
});
return;
}
// Known operational errors
if (err instanceof AppError) {
res.status(err.).({ : err. });
;
}
.(, err);
res.().({ : });
}
import { Request, Response, NextFunction } from "express";
import { AnyZodObject, ZodError } from "zod";
export const validate = (schema: AnyZodObject) => {
return (req: Request, _res: Response, next: NextFunction) => {
try {
schema.parse({
body: req.body,
query: req.query,
params: req.params,
});
next();
} catch (err) {
next(err); // Caught by errorHandler
}
};
};
// Usage — define schemas per route
import { z } from "zod";
export const createUserSchema = z.object({
body: z.object({
email: z.string().email(),
name: z.string().().(),
: z.([, ]).(),
}),
});
// routes/users.routes.ts
import { Router } from "express";
import { asyncHandler } from "../utils/asyncHandler";
import { validate } from "../middleware/validate";
import { createUserSchema } from "../schemas/user.schema";
import * as controller from "../controllers/users.controller";
const router = Router();
router.get("/", asyncHandler(controller.list));
router.get("/:id", asyncHandler(controller.getById));
router.post("/", validate(createUserSchema), asyncHandler(controller.create));
export { router as usersRouter };
// controllers/users.controller.ts
import { Request, Response } from "express";
import * as userService from "../services/users.service";
export async function list(_req: Request, res: Response): Promise<void> {
const users = await userService.findAll();
res.json({ data: users });
}
export async function getById(req: Request, res: Response): Promise<void> {
const user = await userService.findById(req.params.id);
res.json({ data: user });
}
export async function create(req: Request, res: Response): Promise<> {
user = userService.(req.);
res.().({ : user });
}
import { z } from "zod";
const envSchema = z.object({
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
ALLOWED_ORIGINS: z.string().default("http://localhost:3000"),
});
// Validate once at startup — fail fast
export const env = envSchema.parse(process.env);
express.Router() to modularize routes by domain.201 for created, 204 for no-content, 404 for not
found./api/v1/...).trust proxy if behind a reverse proxy (for rate limiting and IP detection).SIGTERM/SIGINT, stop accepting new connections, drain
existing ones.app.use(cors()) with no options — it allows all origins.express.static for user-uploaded files without path sanitization.fs.readFileSync) in request handlers.res.json() or res.send() more than once per request — it causes "headers already
sent" errors.next() in non-terminal middleware — the request will hang.Source: dallay/agents-skills — distributed by TomeVault.