create-hest-app
Version:
Create HestJS-powered applications with one command
563 lines (450 loc) • 14.6 kB
Markdown
# HestJS Application 🚀
一个基于 **HestJS** 框架的现代化 TypeScript 演示应用,展示了类似 NestJS 的开发体验,但具有更轻量和更高性能的特点。内置支持通过注解自动生成 **OpenAPI 3.0** 规范的 Swagger 文档。
[](https://www.typescriptlang.org/)
[](https://bun.sh/)
[](https://hono.dev/)
[](https://swagger.io/specification/)
[](https://scalar.com/)
[](LICENSE)
## ✨ 主要特性
- 🎯 **类 NestJS 语法**:熟悉的装饰器和模块化架构
- ⚡ **极致性能**:基于 Hono 和 Bun,提供卓越的运行时性能
- 📚 **自动 API 文档**:通过注解自动生成 OpenAPI 3.0 规范
- 🎨 **美观文档界面**:集成 Scalar,提供现代化的 API 文档体验
- 🔧 **依赖注入**:完整的 IoC 容器支持
- 🛡️ **类型安全**:完全的 TypeScript 支持
- 🚀 **快速开发**:热重载和快速构建
## 📖 API 文档
本应用集成了强大的 API 文档功能,支持通过注解自动生成符合 OpenAPI 3.0 规范的 Swagger 文档:
### 🌐 在线访问
启动应用后,可通过以下地址访问 API 文档:
- **📱 Scalar UI**: [http://localhost:3002/docs](http://localhost:3002/docs) - 现代化的交互式 API 文档界面
- **📄 OpenAPI JSON**: [http://localhost:3002/openapi.json](http://localhost:3002/openapi.json) - 原始 OpenAPI 3.0 规范文件
- **🤖 Markdown**: [http://localhost:3002/api-docs.md](http://localhost:3002/api-docs.md) - 为 LLM 优化的 Markdown 格式文档
### 🔧 注解支持
使用简单的装饰器即可为你的 API 生成完整的文档:
#### 控制器级别注解
```typescript
import { Controller, Get, Post } from '@hestjs/core';
import { ApiTags, ApiOperation, ApiResponse } from '@hestjs/scalar';
@Controller('/api/users')
@ApiTags('Users') // 为控制器添加标签
export class UsersController {
// ...
}
```
#### 方法级别注解
```typescript
@Get('/')
@ApiOperation({
summary: 'Get all users',
description: 'Returns a list of all users in the system',
tags: ['Users', 'List'], // 可以覆盖控制器级别的标签
})
@ApiResponse('200', {
description: 'Successful response',
content: {
'application/json': {
schema: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'string', example: '' },
name: { type: 'string', example: 'John Doe' },
email: { type: 'string', format: 'email', example: 'john@example.com' },
},
},
},
},
},
})
async getUsers() {
return this.usersService.findAll();
}
```
#### 参数注解
```typescript
@Get('/:id')
@ApiParam('id', {
description: 'User unique identifier',
schema: { type: 'string' },
example: '1',
})
@ApiResponse('200', {
description: 'User found',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
},
},
},
},
})
@ApiResponse('404', {
description: 'User not found',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
message: { type: 'string', example: 'User not found' },
},
},
},
},
})
async getUserById(@Param('id') id: string) {
return this.usersService.findById(id);
}
```
#### 请求体注解
```typescript
@Post('/')
@ApiOperation({
summary: 'Create a new user',
description: 'Creates a new user with the provided data',
})
@ApiBody(
{
'application/json': {
schema: {
type: 'object',
required: ['name', 'email'],
properties: {
name: { type: 'string', example: 'John Doe' },
email: {
type: 'string',
format: 'email',
example: 'john@example.com'
},
},
},
},
},
{
description: 'User creation data',
required: true,
}
)
@ApiResponse('201', {
description: 'User created successfully',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
},
},
},
},
})
async createUser(@Body() userData: CreateUserDto) {
return this.usersService.create(userData);
}
```
### 🎨 可用装饰器
| 装饰器 | 用途 | 示例 |
| ------------------------------ | ---------------------- | ------------------------------------------------ |
| `@ApiTags(...)` | 为控制器或方法添加标签 | `@ApiTags('Users', 'Admin')` |
| `@ApiOperation(...)` | 描述 API 操作 | `@ApiOperation({ summary: '获取用户' })` |
| `@ApiResponse(status, spec)` | 定义响应格式 | `@ApiResponse('200', { description: '成功' })` |
| `@ApiParam(name, spec)` | 描述路径参数 | `@ApiParam('id', { type: 'string' })` |
| `@ApiQuery(name, spec)` | 描述查询参数 | `@ApiQuery('page', { type: 'number' })` |
| `@ApiBody(schema, options)` | 描述请求体 | `@ApiBody({ schema: userSchema })` |
### ⚙️ 配置选项
```typescript
// 在 main.ts 中配置 API 文档
app.useScalarWithControllers(
[AppController, UsersController], // 需要生成文档的控制器
{
// OpenAPI 基本信息
info: {
title: 'HestJS Demo API',
version: '1.0.0',
description: 'HestJS 框架演示应用的 API 文档',
contact: {
name: 'API Support',
email: 'support@example.com',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
},
// 服务器配置
servers: [
{
url: 'http://localhost:3002',
description: 'Development server',
},
{
url: 'https://api.example.com',
description: 'Production server',
},
],
},
{
// Scalar 配置
path: '/docs', // 文档访问路径
theme: 'elysia', // 主题样式
title: 'HestJS API Documentation', // 页面标题
enableMarkdown: true, // 启用 Markdown 导出
markdownPath: '/api-docs.md', // Markdown 访问路径
}
);
```
## 🏗️ 项目结构
```
src/
├── index.ts # 应用入口点
├── app.module.ts # 根模块
├── app.controller.ts # 应用控制器(含 API 文档注解示例)
├── app.service.ts # 应用服务
├── common/ # 公共组件
│ ├── filters/ # 全局过滤器
│ │ └── http-exception.filter.ts
│ └── interceptors/ # 全局拦截器
│ └── response.interceptor.ts
└── modules/ # 功能模块
├── users/ # 用户模块
│ ├── dto/ # 数据传输对象
│ │ └── user.dto.ts
│ ├── users.controller.ts # 用户控制器(含完整 API 注解)
│ ├── users.service.ts
│ └── users.module.ts
└── custom-validation/ # 自定义验证模块
├── dto/
│ └── custom-validation.dto.ts
├── custom-validation.controller.ts
├── custom-validation.service.ts
└── custom-validation.module.ts
```
## 🚀 快速开始
### 前置要求
- [Bun](https://bun.sh/) >= 1.0.0
- Node.js >= 18.0.0 (可选,Bun 包含 Node.js 兼容层)
### 安装依赖
```bash
bun install
```
### 开发环境
```bash
# 开发模式(热重载)
bun run dev
# 或者在 monorepo 根目录
turbo run dev --filter=@hestjs/demo
```
### 构建和部署
```bash
# 构建
bun run build
# 生产环境运行
bun run start:prod
# 创建独立可执行文件
bun run build:binary
./dist/hest-demo
```
## 📡 API 文档
### 基础端点
- `GET /api` - 应用信息
- `GET /api/health` - 健康检查
### 用户管理 (`/users`)
- `GET /users` - 获取所有用户
- `GET /users/:id` - 获取特定用户
- `POST /users` - 创建新用户
- `POST /users/:id` - 更新用户信息
#### 请求示例:
```bash
# 创建用户
curl -X POST http://localhost:3002/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"password": "password123"
}'
```
### 自定义验证 (`/api/custom`)
- `GET /api/custom` - 验证功能说明
- `POST /api/custom/validate` - 测试自定义验证
- `POST /api/custom/search` - 测试搜索参数验证
- `GET /api/custom/examples` - 获取验证示例
#### 请求示例:
```bash
# 自定义验证
curl -X POST http://localhost:3002/api/custom/validate \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe123",
"role": "user",
"userId": "123e4567-e89b-12d3-a456-426614174000",
"phoneNumber": "13812345678",
"location": { "lat": 39.9042, "lng": 116.4074 },
"emails": ["john@example.com", "john.doe@company.com"]
}'
```
## 🛠️ 核心功能
### 1. 模块化架构
- **清晰的模块分离**:每个功能模块都有自己的控制器、服务、DTO 和实体
- **依赖注入**:使用 `@Injectable()` 和 `@Module()` 装饰器
- **模块导入/导出**:支持模块间的依赖关系
### 2. 强类型验证
- **TypeBox 集成**:使用 TypeBox 进行运行时类型验证
- **自定义验证器**:支持复杂的业务逻辑验证
- **联合类型支持**:支持 TypeScript 的高级类型特性
### 3. 中间件和拦截器
- **全局异常过滤器**:统一的错误处理
- **响应拦截器**:统一的响应格式
- **CORS 支持**:跨域资源共享配置
- **请求日志**:自动记录请求和响应
### 4. 配置管理
- **环境变量支持**:通过 `.env` 文件配置
- **类型安全配置**:使用 TypeScript 确保配置的类型安全
### 5. CQRS 支持
- **命令查询职责分离**:支持 CQRS 架构模式
- **事件驱动**:内置事件总线支持
- **命令和查询处理器**:独立的命令和查询处理逻辑
- **事件溯源**:支持事件驱动的业务逻辑
> 📝 **CQRS 演示应用**:完整的 CQRS 实现示例请参考 [HestJS CQRS Demo](https://github.com/aqz236/hestjs-cqrs-demo)
## 🔧 验证功能展示
### 基础验证
```typescript
export class CreateUserDto {
@IsString({ minLength: 2, maxLength: 50 })
name!: string;
@IsEmail()
email!: string;
@IsNumber()
@Min(0)
@Max(120)
age!: number;
}
```
### 高级验证
```typescript
export class CustomValidationDto {
// 正则表达式验证
@Custom(
Type.String({ minLength: 3, maxLength: 20, pattern: '^[a-zA-Z0-9_]+$' }),
{ message: '用户名必须是3-20位字母、数字或下划线' },
)
username!: string;
// 联合类型验证
@Custom(
Type.Union([
Type.Literal('admin'),
Type.Literal('user'),
Type.Literal('guest'),
]),
{ message: '角色必须是 admin、user 或 guest' },
)
role!: 'admin' | 'user' | 'guest';
// UUID 验证
@CommonValidators.UUID()
userId!: string;
// 中国手机号验证
@Custom(SchemaFactory.chinesePhoneNumber(), { optional: true })
phoneNumber?: string;
// 嵌套对象验证
@Custom(
Type.Object({
lat: Type.Number({ minimum: -90, maximum: 90 }),
lng: Type.Number({ minimum: -180, maximum: 180 }),
}),
{ optional: true },
)
location?: { lat: number; lng: number };
}
```
## 🎯 架构特点
### 1. NestJS 风格的目录结构
- 模块化组织:每个功能模块独立管理
- 清晰的职责分离:控制器、服务、DTO、实体分离
- 可扩展性:易于添加新功能模块
### 2. 现代 TypeScript 开发
- 严格的类型检查
- 装饰器模式
- 依赖注入
- 接口优先设计
### 3. 高性能运行时
- Bun 运行时支持
- Hono 高性能 Web 框架
- 端口复用优化
- 生产环境优化
### 4. CQRS 架构支持
- 命令查询职责分离模式
- 事件驱动架构
- 独立的读写模型
- 可扩展的处理器模式
> 🔗 **完整 CQRS 示例**:查看专门的 CQRS 演示应用 → [HestJS CQRS Demo](https://github.com/aqz236/hestjs-cqrs-demo)
## 📦 部署
### Docker 部署
```dockerfile
FROM oven/bun:1 as base
WORKDIR /app
# 复制依赖文件
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
# 复制源代码
COPY . .
# 构建应用
RUN bun run build
# 运行应用
CMD ["bun", "run", "start:prod"]
EXPOSE 3002
```
### 二进制部署
```bash
# 构建独立可执行文件
bun run build:binary
# 部署单个文件
./dist/hest-demo
```
## 🧪 测试
```bash
# 运行测试
bun test
# 覆盖率测试
bun test --coverage
```
## 📝 开发指南
### 添加新模块
1. 在 `src/modules/` 下创建新目录
2. 创建 `*.module.ts`、`*.controller.ts`、`*.service.ts`
3. 在 `app.module.ts` 中导入新模块
### 添加验证规则
1. 在模块的 `dto/` 目录下创建 DTO 类
2. 使用 `@Custom()` 装饰器定义验证规则
3. 在控制器中使用 `@Body()` 装饰器应用验证
### 环境配置
```bash
# .env 文件
PORT=3002
NODE_ENV=development
CORS_ORIGIN=*
```
## 🔗 相关项目
### HestJS CQRS Demo
完整的 CQRS(命令查询职责分离)架构演示应用,展示了如何在 HestJS 框架中实现:
- ✅ 命令处理器 (Command Handlers)
- ✅ 查询处理器 (Query Handlers)
- ✅ 事件处理器 (Event Handlers)
- ✅ 事件总线 (Event Bus)
- ✅ 用户管理完整流程
🔗 **仓库地址**:[https://github.com/aqz236/hestjs-cqrs-demo](https://github.com/aqz236/hestjs-cqrs-demo)
该项目展示了在现代 TypeScript 应用中如何优雅地实现 CQRS 模式,适合需要复杂业务逻辑和高可扩展性的企业级应用。
## 🤝 贡献
欢迎提交 Issue 和 Pull Request!
## 📄 许可证
MIT License