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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aqcq/express-reply

v0.2.1

Published

Express Reply middleware

Readme

@aqcq/express-reply

Express Reply middleware,为 Express Response 对象添加统一的响应方法和自动错误捕获功能。

特色功能

自动错误捕获 - 无需手动调用 next(error),直接 throw 即可
🚀 统一响应格式 - 标准化成功和错误响应结构
📝 完整 TypeScript 支持 - 类型提示和自动补全
🔧 灵活配置 - 支持预定义和自定义错误类型

安装

npm install @aqcq/express-reply
# 或
yarn add @aqcq/express-reply

核心功能

🎯 自动错误捕获(推荐方式)

使用 catchError 包装器,让你可以直接 throw 错误,无需调用 next()

import express from 'express';
import { errorMiddleware, ResponseError, catchError } from '@aqcq/express-reply';

const app = express();

// 异步路由 - 自动捕获错误
app.get('/api/user/:id', catchError(async (req, res) => {
  const { id } = req.params;
  
  if (id === '404') {
    // 直接抛出错误,无需 next()!
    throw new ResponseError('VALIDATION_ERROR');
  }
  
  // 模拟异步数据库操作
  const user = await getUserFromDB(id);
  res.reply(user);
}));

// 同步路由 - 自动捕获错误
app.get('/api/sync', catchError((req, res) => {
  // 同步代码中也可以直接抛出错误
  throw new ResponseError('HTTP_ERROR');
}));

// 错误处理中间件(必须放在最后)
app.use(errorMiddleware());
app.listen(3000);

🔧 针对性错误捕获

如果你明确知道路由是同步还是异步的,可以使用更具体的包装器:

import { asyncHandler, syncHandler } from '@aqcq/express-reply';

// 专门用于异步路由
app.get('/api/async', asyncHandler(async (req, res) => {
  await someAsyncOperation();
  throw new ResponseError('REQUEST_AI_ERROR');
}));

// 专门用于同步路由
app.get('/api/sync', syncHandler((req, res) => {
  throw new ResponseError('RATE_LIMIT_ERROR');
}));

📋 传统方式(向后兼容)

如果不使用错误捕获包装器,仍需手动调用 next()

app.get('/api/traditional', async (req, res, next) => {
  try {
    throw new ResponseError('VALIDATION_ERROR');
  } catch (error) {
    next(error); // 传统方式需要手动调用
  }
});

✅ 统一响应格式

使用内置的响应方法来标准化你的API响应:

import express from 'express';
import { replyMiddleware, catchError } from '@aqcq/express-reply';

const app = express();

// 注册 reply 中间件
app.use(replyMiddleware);

app.get('/api/success', catchError(async (req, res) => {
  // 成功响应 - 统一格式
  res.reply({ 
    message: 'Hello World', 
    data: { id: 1, name: '用户名' } 
  });
}));

app.get('/api/fail', catchError((req, res) => {
  // 方式1: 直接使用响应方法
  res.replyFail('VALIDATION_ERROR');
  
  // 方式2: 抛出错误(推荐)
  // throw new ResponseError('VALIDATION_ERROR');
}));

app.listen(3000);

TypeScript 支持

本包提供完整的 TypeScript 类型支持。安装后,你的 Express Response 对象会自动扩展以下方法:

interface Response {
  reply: (data: any) => void;
  replyFail: (name: ErrorName) => void;
}

在 TypeScript 项目中使用时,你会获得完整的类型提示和自动补全:

import express from 'express';
import { replyMiddleware, ErrorName } from '@aqcq/express-reply';

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

app.get('/api/users', (req, res) => {
  // TypeScript 会为 res.reply 和 res.replyFail 提供类型提示
  res.reply({ users: [] });
  res.replyFail('USER_LIMIT_ERROR'); // 错误名称会有自动补全
});

API 参考

错误捕获包装器

catchError(handler) - 推荐使用

通用错误捕获包装器,自动处理同步和异步错误:

import { catchError } from '@aqcq/express-reply';

app.get('/api/route', catchError(async (req, res) => {
  // 可以是同步或异步函数
  throw new ResponseError('VALIDATION_ERROR');
}));

asyncHandler(handler)

专门用于异步路由的错误捕获:

import { asyncHandler } from '@aqcq/express-reply';

app.get('/api/async', asyncHandler(async (req, res) => {
  await someAsyncOperation();
  throw new ResponseError('REQUEST_AI_ERROR');
}));

syncHandler(handler)

专门用于同步路由的错误捕获:

import { syncHandler } from '@aqcq/express-reply';

app.get('/api/sync', syncHandler((req, res) => {
  throw new ResponseError('HTTP_ERROR');
}));

响应方法

res.reply(data)

发送成功响应。

  • data: 要返回的数据(任意类型)

响应格式:

{
  "code": 0,
  "message": "success",
  "timestamp": 1234567890,
  "data": "你传入的数据"
}

res.replyFail(errorName, code?)

发送错误响应。

  • errorName: 错误名称(预定义类型或自定义字符串)
  • code: 可选的错误码,默认为 5000

响应格式:

{
  "code": 2001,
  "message": "parameter validation error",
  "success": false
}

错误类

new ResponseError(message, code?)

创建一个可以被错误中间件捕获的错误实例。

  • message: 错误名称(预定义类型)或自定义错误消息
  • code: 可选的错误码,默认为 500
// 使用预定义错误类型
throw new ResponseError('VALIDATION_ERROR');

// 使用自定义错误消息和错误码
throw new ResponseError('自定义错误消息', 4001);

支持的错误类型及错误码

[
  {
    code: 1001,
    name: 'HTTP_ERROR',
    message: 'internal unknown error',
    _apiDesc: '内部未知错误',
  },
  {
    code: 2001,
    name: 'VALIDATION_ERROR',
    message: 'parameter validation error',
    _apiDesc: '参数校验错误',
  },
  {
    code: 4002,
    name: 'REQUEST_AI_ERROR',
    message: 'requestAI error',
  },
  {
    code: 4003,
    name: 'USER_LIMIT_ERROR',
    message:
      'The limit for current model has been reached. Please wait until the next period or upgrade your plan to get more.',
  },
  {
    code: 4003,
    name: 'NOT_BASE_BOT_USAGE_LIMIT_ERROR',
    message:
      'The monthly queries for GPT-4, which this bot is based on, has been exhausted. Please use another bot.',
  },
  {
    code: 4004,
    name: 'USAGE_LIMIT_FOR_FREE_ERROR',
    message:
      'Free users can only use the standard model ( 10 queries per day ). Please try again tomorrow or upgrade your plan to get more.',
  },
  {
    code: 4005,
    name: 'BASE_BOT_NOT_FOUND_ERRO',
    message:
      'The base bot for your current bot has been deleted. Please reconfigure another base robot.',
  },
  {
    code: 4006,
    name: 'ONLY_USE_GPT3DOT5_ERROR',
    message:
      'Your complimentary queries has been exhausted, you can now only use GPT-3.5 (10 queries per day).',
  },
  {
    code: 4008,
    name: 'REQUEST_AI_WITH_NETWORK_AUTH_ERROR',
    message: 'Unauthorized',
  },
  {
    code: 4009,
    name: 'ONLY_USE_BASIC_BOT_ERROR',
    message:
      'The advanced drawing model is not available for free users. Upgrade your plan to get more advanced features.',
  },
  {
    code: 4010,
    name: 'BOT_NETWORK_ERROR',
    message: 'Internet access is not available for free users.',
  },
  {
    code: 4011,
    name: 'ONLY_PRO_USER_CAN_USE_ERRO',
    message: 'insufficient User Permissions',
    _apiDesc: 'insufficient User Permissions',
  },
  {
    code: 4012,
    name: 'AI_USE_PRO_ERROR',
    message: 'The advanced drawing model is not available for Air Plan.Please upgrade your plan.',
  },
  {
    code: 4013,
    name: 'MODEL_NOT_FOUND_ERROR',
    message: 'Model not found',
    _apiDesc: 'Model not found',
  },
  {
    code: 4014,
    name: 'MODEL_UNAVAILABLE_ERROR',
    message: 'The model you are using is not available. Please try another model.',
  },
  {
    code: 4015,
    name: 'MODEL_UNAVAILABLE_ERROR',
    message: 'Model unavailable',
    _apiDesc: 'Model unavailable',
  },
  {
    code: 5001,
    name: 'CREATE_ACTION_ERROR',
    message: 'Creation failure',
    _apiDesc: 'Creation failure',
  },
  {
    code: 5040,
    name: 'RESPONSE_MODEL_NOT_FOUND_ERRO',
    message: 'model not found',
    _apiDesc: '模型不存在',
  },
  {
    code: 5041,
    name: 'RESPONSE_GEN_TITLE_ERROR',
    message: 'generate title failed',
    _apiDesc: '生成标题失败',
  },
  {
    code: 5042,
    name: 'RESPONSE_QUERY_ERROR',
    message: 'query failed',
    _apiDesc: '查询失败',
  },
  {
    code: 5043,
    name: 'RESPONSE_BOT_OPERATION_ERROR',
    message: 'operation failed',
    _apiDesc: 'bot操作失败',
  },
  {
    code: 5044,
    name: 'RESPONSE_BOT_EXISTS_ERROR',
    message: 'Bot already exists',
    _apiDesc: 'bot已存在',
  },
  {
    code: 6001,
    name: 'RATE_LIMIT_ERROR',
    message: 'Request rate limit',
    _apiDesc: 'Creation failure',
  },
]

完整的错误类型列表请参考源码中的 ERROR_MESSAGES

最佳实践

✅ 推荐做法

import { replyMiddleware, errorMiddleware, catchError, ResponseError } from '@aqcq/express-reply';

const app = express();

// 1. 注册 reply 中间件
app.use(replyMiddleware);

// 2. 使用 catchError 包装所有路由
app.get('/api/users', catchError(async (req, res) => {
  // 3. 直接抛出错误,无需 next()
  if (!req.user) {
    throw new ResponseError('VALIDATION_ERROR');
  }
  
  // 4. 使用统一的响应格式
  res.reply({ users: await getUsers() });
}));

// 5. 错误处理中间件放在最后
app.use(errorMiddleware());

❌ 避免的做法

// 不推荐:混合使用传统方式和新方式
app.get('/api/bad', async (req, res, next) => {
  try {
    throw new ResponseError('ERROR');
  } catch (error) {
    next(error); // 多余的 next() 调用
  }
});

// 不推荐:忘记使用错误捕获包装器
app.get('/api/bad2', async (req, res, next) => {
  throw new ResponseError('ERROR'); // 异步错误不会被捕获
});

注意事项

  1. 中间件顺序很重要

    • replyMiddleware 要在业务路由之前注册
    • errorMiddleware 要在所有路由之后注册
  2. 错误捕获

    • 使用 catchError 包装器可以自动捕获所有错误
    • 不使用包装器时,异步错误需要手动调用 next(error)
  3. 响应格式

    • res.reply()res.replyFail() 会自动设置适当的 HTTP 状态码
    • 调用后响应立即发送,无需手动调用其他响应方法
  4. TypeScript 支持

    • 包含完整的类型定义,提供最佳的开发体验
    • 错误名称会有自动补全功能

License

MIT