# @fishka/express 中文文档

规范地址：https://npmcn.com/package/%40fishka/express/

版本：0\.9\.25
npm 元数据更新时间：2026-01-29T03:27:41.174Z
中文译文更新时间：2026-11-14T20:28:22.972Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40fishka/express
原文对照：https://npmcn.com/package/%40fishka/express/?lang=original
源码仓库：https://gitea.com/fishka/express

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：209 kB，110 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.0\.0
- 运行依赖：2 个
- 首次发布：2026-01-07T04:35:58.568Z
- 最新版本发布：2026-01-29T03:27:41.060Z
- 近 30 天下载量：6161（2026-10-15 至 2026-11-13，npm 官方下载统计）
- 已发布版本数：21（近 12 个月 21 个）

## 中文简介

Express.js 有内置验证的扩展和类型安全

## 安装

```sh
npm install @fishka/express
```

也可以使用：`pnpm add @fishka/express`、`yarn add @fishka/express`、`bun add @fishka/express`

## README

# 快捷 API

Express.js的功能公用事业,具有类型安全验证和出错处理功能.

## 安装

```bash
npm install @fishka/express
```

## 概览

这个软件包提供了与Express直接合作的独立公用功能. 每个特性都可以独立使用——混合并匹配你所需要的.

## 快速启动

```typescript
import express from 'express';
import { addErrorHandling, body, patchExpressAsyncErrors, pathParam, queryParam } from '@fishka/express';
import { assertString } from '@fishka/assertions';

const app = express();
app.use(express.json());

// Enable automatic async error catching (call once at startup)
patchExpressAsyncErrors();

// GET /users/:id - with typed path params
app.get('/users/:id', async (req, res) => {
  const id = pathParam(req, 'id'); // string - validated inline
  res.json({ id, name: 'John' });
});

// GET /users - with query params
app.get('/users', async (req, res) => {
  const page = queryParam(req, 'page'); // string - throws 400 if missing
  res.json({ page, users: [] });
});

// POST /users - with body validation
app.post('/users', async (req, res) => {
  const data = body(req, { name: assertString });
  res.json({ id: 1, name: data.name }); // validators infer a type for the data!
});

// Add error handling middleware (must be last)
addErrorHandling(app);

app.listen(3000);
```

## 公用事业

### `pathParam(req, name, validator?)`

从Express请求获取并验证路径参数.

```typescript
import { pathParam, transform, toInt, minLength } from '@fishka/express';

app.get('/users/:id', async (req, res) => {
  // Simple - returns string, throws 400 if missing
  const id1 = pathParam(req, 'id');

  // With validation - transform to number
  const id2 = pathParam(req, 'id', transform(toInt()));

  // Transform with validation - string min length
  const slug = pathParam(req, 'slug', transform(minLength(3)));

  res.json({ id: '...' });
});
```

### `queryParam(req, name, validator?)`

从Express请求获取并验证查询参数.

```typescript
import { queryParam, transform, toInt, min, range, oneOf } from '@fishka/express';

app.get('/users', async (req, res) => {
  // Simple - returns string, throws 400 if missing
  const search = queryParam(req, 'search');

  // With validation - transform to number with min value
  const page = queryParam(req, 'page', transform(toInt(), min(1)));

  // With validation - number range
  const limit = queryParam(req, 'limit', transform(toInt(), range(1, 100)));

  // With validation - enum
  const sort = queryParam(req, 'sort', transform(oneOf('asc', 'desc')));

  res.json({ page, limit, users: [] });
});
```

### `body(req, validator)`

获取并验证请求机构.

```typescript
import { body } from '@fishka/express';
import { assertString, assertNumber } from '@fishka/assertions';

app.post('/users', async (req, res) => {
  // Object assertion - validates and infers a type.
  const data = body(req, {
    name: assertString,
    age: assertNumber,
  });

  res.json({ id: 1, name: data.name });
});
```

### `patchExpressAsyncErrors()`

补丁快取以自动捕获同步错误 。 应用程序启动时呼叫一次 .

```typescript
import { patchExpressAsyncErrors } from '@fishka/express';

// Call before defining routes
patchExpressAsyncErrors();

// Now async route handlers don't need try/catch
app.get('/users', async (req, res) => {
  const users = await db.users.findAll(); // Errors are caught automatically
  res.json(users);
});
```

### `addErrorHandling(app)`

添加处理中间软件的集中错误 。 必须在所有路线后呼叫.

```typescript
import { addErrorHandling, HttpError } from '@fishka/express';

// Define routes...
app.get('/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id);
  assertHttp(user, 404, 'User not found');
  res.json(user);
});

// Add error handling last
addErrorHandling(app);
```

## 参数验证

使用 `transform()` 用于验证和转换参数。 所有运算符都是可复合的 :

```typescript
import { transform, toInt, minLength, matches, min, range, oneOf } from '@fishka/express';

app.get('/users/:id', async (req, res) => {
  const id = pathParam(req, 'id', transform(toInt())); // string → number
  const page = queryParam(req, 'page', transform(toInt(), min(1))); // number >= 1
  const limit = queryParam(req, 'limit', transform(toInt(), range(1, 100))); // number 1-100
  const sort = queryParam(req, 'sort', transform(oneOf('asc', 'desc'))); // enum
  const search = queryParam(req, 'search', transform(minLength(3))); // string min 3 chars

  res.json({ id, page, limit });
});
```

### 可用的运算符

**转换(字符串-T):**

-   `toInt()` - 解为整数
-   `toNumber()` - 解说数字
-   `toBool()` - 分析"真"/"假"以布尔
-   `oneOf('a', 'b')` - 激发值

**字符串验证器 :**

-   `minLength(n)` - 最小长度
-   `maxLength(n)` - 最大长度
-   `matches(/regex/)` - 正则匹配
-   `trim` - 修剪白空间
-   `lowercase` 编号 : `uppercase` - 案件转换

**数字验证符 :**

-   `min(n)` - 最低价值
-   `max(n)` - 最大值
-   `range(min, max)` - 数值范围

**常规 :**

-   `transform(...ops)` - 验证器/转换器链
-   `check(predicate, msg)` - 带有上游的自定义验证
-   `validator(fn)` - 返回字符串的自定义验证器
-   `map(fn)` - 转换价值

### 所需参数

-   `pathParam(req, 'name')` - 返回字符串( 如果缺少的话, 移动400)
-   `queryParam(req, 'name')` - 返回字符串( 如果缺少/ 空)
-   `queryParam(req, 'name', validator)` - 返回已验证的值( 如果缺少/ 空/ 无效, 则扔出 400)
-   所有参数都需要 - 缺少或空值丢出 BAD REQEST

## 认证

```typescript
import { createAuthMiddleware, BasicAuthStrategy, getAuthUser } from '@fishka/express';

const auth = new BasicAuthStrategy(async (user, pass) =>
  user === 'admin' && pass === 'secret' ? { id: '1', role: 'admin' } : null,
);

app.get('/profile', createAuthMiddleware(auth), async (req, res) => {
  const user = getAuthUser(req);
  res.json({ id: user.id });
});
```

## 限制费率

```typescript
import { createRateLimiterMiddleware } from '@fishka/express';

app.use(
  await createRateLimiterMiddleware({
    points: { read: 100, write: 50 },
    duration: 60,
  }),
);
```

## HTTP 错误

使用 `HttpError` 特定状态代码:

```typescript
import { HttpError, HTTP_UNAUTHORIZED, HTTP_NOT_FOUND } from '@fishka/express';

app.get('/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id);

  if (!req.headers.authorization) {
    throw new HttpError(HTTP_UNAUTHORIZED, 'Authorization required');
  }

  if (!user) {
    throw new HttpError(HTTP_NOT_FOUND, 'User not found');
  }

  res.json(user);
});
```

使用 `assertHttp` 内在断言:

```typescript
import { assertHttp, HTTP_UNAUTHORIZED, HTTP_NOT_FOUND } from '@fishka/express';

app.get('/admin', async (req, res) => {
  assertHttp(req.headers.authorization, HTTP_UNAUTHORIZED, 'Authorization required');

  const user = await db.users.findById(req.params.id);
  assertHttp(user, HTTP_NOT_FOUND, 'User not found');
  assertHttp(user.isAdmin, HTTP_FORBIDDEN, 'Admin access required');

  res.json({ admin: true });
});
```

## 配置

### 请求编号

```typescript
import { configureExpressApi, createTlsMiddleware } from '@fishka/express';

// Enable request ID with custom header name
configureExpressApi({
  requestIdHeader: 'x-request-id', // or 'x-correlation-id', 'trace-id', etc.
  trustRequestIdHeader: true, // default: true, if we trust and propagate request ID passed by client.
});

// Add TLS middleware to track request context
app.use(createTlsMiddleware());
```

### 处理器

处理未发现的错误和优雅的关闭 :

```typescript
import { installProcessHandlers } from '@fishka/express';

installProcessHandlers({
  onUncaughtException: err => sendToMonitoring(err),
  onUnhandledRejection: reason => sendToMonitoring(reason),
  onShutdown: async () => {
    await database.close();
    await server.close();
  },
  shutdownTimeout: 15000,
});
```

## 完整示例

```typescript
import express from 'express';
import {
  addErrorHandling,
  body,
  min,
  patchExpressAsyncErrors,
  pathParam,
  queryParam,
  range,
  toInt,
  transform,
} from '@fishka/express';
import { assertString } from '@fishka/assertions';
import { assertHttp } from './api.types';

const app = express();
app.use(express.json());

// Enable automatic async error catching
patchExpressAsyncErrors();

// Routes
app.get('/users/:id', async (req, res) => {
  const id = pathParam(req, 'id', transform(toInt()));
  const user = await db.users.findById(id);
  assertHttp(user, 404, 'User not found');
  res.json(user);
});

app.get('/users', async (req, res) => {
  const page = queryParam(req, 'page', transform(toInt(), min(1)));
  const limit = queryParam(req, 'limit', transform(toInt(), range(1, 100)));

  const users = await db.users.findAll({ page, limit });
  res.json({ users, page, limit });
});

app.post('/users', async (req, res) => {
  const data = body(req, { name: assertString });
  const user = await db.users.create(data);
  res.status(201).json(user);
});

// Error handling (must be last)
addErrorHandling(app);

app.listen(3000);
```

## 许可证

麻省理工学院

## 常见问题

### @fishka/express 是什么？

Express\.js 有内置验证的扩展和类型安全

### 如何安装 @fishka/express？

在项目目录运行 npm install @fishka/express，或使用 pnpm add / yarn add / bun add。

### @fishka/express 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @fishka/express 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @fishka/express 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @fishka/express 可以商用吗？

@fishka/express 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @fishka/express 的下载量有多少？

根据 npm 官方下载统计，@fishka/express 在 2026/10/15 – 2026/11/13 这 30 天内被下载 6,161 次，日均约 205 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @fishka/express 还在维护吗？

最新版本 0\.9\.25 发布于 2026/01/29（9 个月前）；至今共发布 21 个版本，其中过去 12 个月发布了 21 个；首次发布于 2026/01/07。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

