create-hest-app 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +211 -0
- package/dist/index.js +127 -0
- package/package.json +50 -0
- package/templates/base/.prettierrc +33 -0
- package/templates/base/.vscode/extensions.json +79 -0
- package/templates/base/.vscode/settings.json +70 -0
- package/templates/base/README.md +562 -0
- package/templates/base/eslint.config.ts +26 -0
- package/templates/base/package.json +62 -0
- package/templates/base/src/app.controller.ts +39 -0
- package/templates/base/src/app.module.ts +12 -0
- package/templates/base/src/app.service.ts +30 -0
- package/templates/base/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/base/src/common/interceptors/response.interceptor.ts +38 -0
- package/templates/base/src/index.ts +35 -0
- package/templates/base/src/modules/custom-validation/custom-validation.controller.ts +146 -0
- package/templates/base/src/modules/custom-validation/custom-validation.module.ts +10 -0
- package/templates/base/src/modules/custom-validation/custom-validation.service.ts +33 -0
- package/templates/base/src/modules/custom-validation/dto/custom-validation.dto.ts +132 -0
- package/templates/base/src/modules/users/dto/user.dto.ts +64 -0
- package/templates/base/src/modules/users/entities/user.entity.ts +9 -0
- package/templates/base/src/modules/users/users.controller.ts +68 -0
- package/templates/base/src/modules/users/users.module.ts +10 -0
- package/templates/base/src/modules/users/users.service.ts +55 -0
- package/templates/base/tsconfig.json +19 -0
- package/templates/base_scalar/.prettierrc +32 -0
- package/templates/base_scalar/.vscode/extensions.json +79 -0
- package/templates/base_scalar/.vscode/settings.json +70 -0
- package/templates/base_scalar/README.md +562 -0
- package/templates/base_scalar/eslint.config.ts +26 -0
- package/templates/base_scalar/package.json +63 -0
- package/templates/base_scalar/src/app.controller.ts +196 -0
- package/templates/base_scalar/src/app.module.ts +12 -0
- package/templates/base_scalar/src/app.service.ts +30 -0
- package/templates/base_scalar/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/base_scalar/src/common/interceptors/response.interceptor.ts +38 -0
- package/templates/base_scalar/src/index.ts +67 -0
- package/templates/base_scalar/src/modules/custom-validation/custom-validation.controller.ts +146 -0
- package/templates/base_scalar/src/modules/custom-validation/custom-validation.module.ts +10 -0
- package/templates/base_scalar/src/modules/custom-validation/custom-validation.service.ts +33 -0
- package/templates/base_scalar/src/modules/custom-validation/dto/custom-validation.dto.ts +132 -0
- package/templates/base_scalar/src/modules/users/dto/user.dto.ts +64 -0
- package/templates/base_scalar/src/modules/users/entities/user.entity.ts +9 -0
- package/templates/base_scalar/src/modules/users/users.controller.ts +68 -0
- package/templates/base_scalar/src/modules/users/users.module.ts +10 -0
- package/templates/base_scalar/src/modules/users/users.service.ts +55 -0
- package/templates/base_scalar/tsconfig.json +19 -0
- package/templates/cqrs/.prettierrc +33 -0
- package/templates/cqrs/.vscode/extensions.json +79 -0
- package/templates/cqrs/.vscode/settings.json +70 -0
- package/templates/cqrs/README.md +234 -0
- package/templates/cqrs/eslint.config.ts +26 -0
- package/templates/cqrs/package.json +62 -0
- package/templates/cqrs/src/app.controller.ts +28 -0
- package/templates/cqrs/src/app.module.ts +12 -0
- package/templates/cqrs/src/app.service.ts +8 -0
- package/templates/cqrs/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/cqrs/src/common/interceptors/response.interceptor.ts +38 -0
- package/templates/cqrs/src/index.ts +38 -0
- package/templates/cqrs/src/modules/custom-validation/custom-validation.controller.ts +146 -0
- package/templates/cqrs/src/modules/custom-validation/custom-validation.module.ts +10 -0
- package/templates/cqrs/src/modules/custom-validation/custom-validation.service.ts +33 -0
- package/templates/cqrs/src/modules/custom-validation/dto/custom-validation.dto.ts +132 -0
- package/templates/cqrs/src/modules/users/dto/user.dto.ts +64 -0
- package/templates/cqrs/src/modules/users/entities/user.entity.ts +9 -0
- package/templates/cqrs/src/modules/users/users.controller.ts +68 -0
- package/templates/cqrs/src/modules/users/users.module.ts +10 -0
- package/templates/cqrs/src/modules/users/users.service.ts +55 -0
- package/templates/cqrs/src/test-error-scenarios.ts +54 -0
- package/templates/cqrs/src/users/commands/create-user.command.ts +8 -0
- package/templates/cqrs/src/users/commands/index.ts +2 -0
- package/templates/cqrs/src/users/commands/update-user.command.ts +11 -0
- package/templates/cqrs/src/users/entities/index.ts +1 -0
- package/templates/cqrs/src/users/entities/user.entity.ts +22 -0
- package/templates/cqrs/src/users/events/index.ts +2 -0
- package/templates/cqrs/src/users/events/user-created.event.ts +8 -0
- package/templates/cqrs/src/users/events/user-updated.event.ts +8 -0
- package/templates/cqrs/src/users/handlers/create-user.handler.ts +26 -0
- package/templates/cqrs/src/users/handlers/get-all-users.handler.ts +15 -0
- package/templates/cqrs/src/users/handlers/get-user.handler.ts +15 -0
- package/templates/cqrs/src/users/handlers/index.ts +6 -0
- package/templates/cqrs/src/users/handlers/update-user.handler.ts +33 -0
- package/templates/cqrs/src/users/handlers/user-created.handler.ts +15 -0
- package/templates/cqrs/src/users/handlers/user-updated.handler.ts +15 -0
- package/templates/cqrs/src/users/index.ts +8 -0
- package/templates/cqrs/src/users/queries/get-all-users.query.ts +8 -0
- package/templates/cqrs/src/users/queries/get-user.query.ts +12 -0
- package/templates/cqrs/src/users/queries/index.ts +2 -0
- package/templates/cqrs/src/users/repositories/index.ts +1 -0
- package/templates/cqrs/src/users/repositories/user.repository.ts +51 -0
- package/templates/cqrs/src/users/user.controller.ts +66 -0
- package/templates/cqrs/src/users/user.module.ts +30 -0
- package/templates/cqrs/tsconfig.json +19 -0
- package/templates/cqrs_scalar/.prettierrc +33 -0
- package/templates/cqrs_scalar/.vscode/extensions.json +79 -0
- package/templates/cqrs_scalar/.vscode/settings.json +70 -0
- package/templates/cqrs_scalar/README.md +234 -0
- package/templates/cqrs_scalar/eslint.config.ts +26 -0
- package/templates/cqrs_scalar/package.json +62 -0
- package/templates/cqrs_scalar/src/app.controller.ts +28 -0
- package/templates/cqrs_scalar/src/app.module.ts +12 -0
- package/templates/cqrs_scalar/src/app.service.ts +8 -0
- package/templates/cqrs_scalar/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/cqrs_scalar/src/common/interceptors/response.interceptor.ts +38 -0
- package/templates/cqrs_scalar/src/index.ts +38 -0
- package/templates/cqrs_scalar/src/modules/custom-validation/custom-validation.controller.ts +146 -0
- package/templates/cqrs_scalar/src/modules/custom-validation/custom-validation.module.ts +10 -0
- package/templates/cqrs_scalar/src/modules/custom-validation/custom-validation.service.ts +33 -0
- package/templates/cqrs_scalar/src/modules/custom-validation/dto/custom-validation.dto.ts +132 -0
- package/templates/cqrs_scalar/src/modules/users/dto/user.dto.ts +64 -0
- package/templates/cqrs_scalar/src/modules/users/entities/user.entity.ts +9 -0
- package/templates/cqrs_scalar/src/modules/users/users.controller.ts +68 -0
- package/templates/cqrs_scalar/src/modules/users/users.module.ts +10 -0
- package/templates/cqrs_scalar/src/modules/users/users.service.ts +55 -0
- package/templates/cqrs_scalar/src/test-error-scenarios.ts +54 -0
- package/templates/cqrs_scalar/src/users/commands/create-user.command.ts +8 -0
- package/templates/cqrs_scalar/src/users/commands/index.ts +2 -0
- package/templates/cqrs_scalar/src/users/commands/update-user.command.ts +11 -0
- package/templates/cqrs_scalar/src/users/entities/index.ts +1 -0
- package/templates/cqrs_scalar/src/users/entities/user.entity.ts +22 -0
- package/templates/cqrs_scalar/src/users/events/index.ts +2 -0
- package/templates/cqrs_scalar/src/users/events/user-created.event.ts +8 -0
- package/templates/cqrs_scalar/src/users/events/user-updated.event.ts +8 -0
- package/templates/cqrs_scalar/src/users/handlers/create-user.handler.ts +26 -0
- package/templates/cqrs_scalar/src/users/handlers/get-all-users.handler.ts +15 -0
- package/templates/cqrs_scalar/src/users/handlers/get-user.handler.ts +15 -0
- package/templates/cqrs_scalar/src/users/handlers/index.ts +6 -0
- package/templates/cqrs_scalar/src/users/handlers/update-user.handler.ts +33 -0
- package/templates/cqrs_scalar/src/users/handlers/user-created.handler.ts +15 -0
- package/templates/cqrs_scalar/src/users/handlers/user-updated.handler.ts +15 -0
- package/templates/cqrs_scalar/src/users/index.ts +8 -0
- package/templates/cqrs_scalar/src/users/queries/get-all-users.query.ts +8 -0
- package/templates/cqrs_scalar/src/users/queries/get-user.query.ts +12 -0
- package/templates/cqrs_scalar/src/users/queries/index.ts +2 -0
- package/templates/cqrs_scalar/src/users/repositories/index.ts +1 -0
- package/templates/cqrs_scalar/src/users/repositories/user.repository.ts +51 -0
- package/templates/cqrs_scalar/src/users/user.controller.ts +66 -0
- package/templates/cqrs_scalar/src/users/user.module.ts +30 -0
- package/templates/cqrs_scalar/tsconfig.json +19 -0
@@ -0,0 +1,562 @@
|
|
1
|
+
# HestJS Demo Application 🚀
|
2
|
+
|
3
|
+
一个基于 **HestJS** 框架的现代化 TypeScript 演示应用,展示了类似 NestJS 的开发体验,但具有更轻量和更高性能的特点。内置支持通过注解自动生成 **OpenAPI 3.0** 规范的 Swagger 文档。
|
4
|
+
|
5
|
+
[](https://www.typescriptlang.org/)
|
6
|
+
[](https://bun.sh/)
|
7
|
+
[](https://hono.dev/)
|
8
|
+
[](https://swagger.io/specification/)
|
9
|
+
[](https://scalar.com/)
|
10
|
+
[](LICENSE)
|
11
|
+
|
12
|
+
## ✨ 主要特性
|
13
|
+
|
14
|
+
- 🎯 **类 NestJS 语法**:熟悉的装饰器和模块化架构
|
15
|
+
- ⚡ **极致性能**:基于 Hono 和 Bun,提供卓越的运行时性能
|
16
|
+
- 📚 **自动 API 文档**:通过注解自动生成 OpenAPI 3.0 规范
|
17
|
+
- 🎨 **美观文档界面**:集成 Scalar,提供现代化的 API 文档体验
|
18
|
+
- 🔧 **依赖注入**:完整的 IoC 容器支持
|
19
|
+
- 🛡️ **类型安全**:完全的 TypeScript 支持
|
20
|
+
- 🚀 **快速开发**:热重载和快速构建
|
21
|
+
|
22
|
+
## 📖 API 文档
|
23
|
+
|
24
|
+
本应用集成了强大的 API 文档功能,支持通过注解自动生成符合 OpenAPI 3.0 规范的 Swagger 文档:
|
25
|
+
|
26
|
+
### 🌐 在线访问
|
27
|
+
|
28
|
+
启动应用后,可通过以下地址访问 API 文档:
|
29
|
+
|
30
|
+
- **📱 Scalar UI**: [http://localhost:3002/docs](http://localhost:3002/docs) - 现代化的交互式 API 文档界面
|
31
|
+
- **📄 OpenAPI JSON**: [http://localhost:3002/openapi.json](http://localhost:3002/openapi.json) - 原始 OpenAPI 3.0 规范文件
|
32
|
+
- **🤖 Markdown**: [http://localhost:3002/api-docs.md](http://localhost:3002/api-docs.md) - 为 LLM 优化的 Markdown 格式文档
|
33
|
+
|
34
|
+
### 🔧 注解支持
|
35
|
+
|
36
|
+
使用简单的装饰器即可为你的 API 生成完整的文档:
|
37
|
+
|
38
|
+
#### 控制器级别注解
|
39
|
+
|
40
|
+
```typescript
|
41
|
+
import { Controller, Get, Post } from '@hestjs/core';
|
42
|
+
import { ApiTags, ApiOperation, ApiResponse } from '@hestjs/scalar';
|
43
|
+
|
44
|
+
@Controller('/api/users')
|
45
|
+
@ApiTags('Users') // 为控制器添加标签
|
46
|
+
export class UsersController {
|
47
|
+
// ...
|
48
|
+
}
|
49
|
+
```
|
50
|
+
|
51
|
+
#### 方法级别注解
|
52
|
+
|
53
|
+
```typescript
|
54
|
+
@Get('/')
|
55
|
+
@ApiOperation({
|
56
|
+
summary: 'Get all users',
|
57
|
+
description: 'Returns a list of all users in the system',
|
58
|
+
tags: ['Users', 'List'], // 可以覆盖控制器级别的标签
|
59
|
+
})
|
60
|
+
@ApiResponse('200', {
|
61
|
+
description: 'Successful response',
|
62
|
+
content: {
|
63
|
+
'application/json': {
|
64
|
+
schema: {
|
65
|
+
type: 'array',
|
66
|
+
items: {
|
67
|
+
type: 'object',
|
68
|
+
properties: {
|
69
|
+
id: { type: 'string', example: 'user-123' },
|
70
|
+
name: { type: 'string', example: 'John Doe' },
|
71
|
+
email: { type: 'string', format: 'email', example: 'john@example.com' },
|
72
|
+
},
|
73
|
+
},
|
74
|
+
},
|
75
|
+
},
|
76
|
+
},
|
77
|
+
})
|
78
|
+
async getUsers() {
|
79
|
+
return this.usersService.findAll();
|
80
|
+
}
|
81
|
+
```
|
82
|
+
|
83
|
+
#### 参数注解
|
84
|
+
|
85
|
+
```typescript
|
86
|
+
@Get('/:id')
|
87
|
+
@ApiParam('id', {
|
88
|
+
description: 'User unique identifier',
|
89
|
+
schema: { type: 'string' },
|
90
|
+
example: 'user-123',
|
91
|
+
})
|
92
|
+
@ApiResponse('200', {
|
93
|
+
description: 'User found',
|
94
|
+
content: {
|
95
|
+
'application/json': {
|
96
|
+
schema: {
|
97
|
+
type: 'object',
|
98
|
+
properties: {
|
99
|
+
id: { type: 'string' },
|
100
|
+
name: { type: 'string' },
|
101
|
+
email: { type: 'string' },
|
102
|
+
},
|
103
|
+
},
|
104
|
+
},
|
105
|
+
},
|
106
|
+
})
|
107
|
+
@ApiResponse('404', {
|
108
|
+
description: 'User not found',
|
109
|
+
content: {
|
110
|
+
'application/json': {
|
111
|
+
schema: {
|
112
|
+
type: 'object',
|
113
|
+
properties: {
|
114
|
+
message: { type: 'string', example: 'User not found' },
|
115
|
+
},
|
116
|
+
},
|
117
|
+
},
|
118
|
+
},
|
119
|
+
})
|
120
|
+
async getUserById(@Param('id') id: string) {
|
121
|
+
return this.usersService.findById(id);
|
122
|
+
}
|
123
|
+
```
|
124
|
+
|
125
|
+
#### 请求体注解
|
126
|
+
|
127
|
+
```typescript
|
128
|
+
@Post('/')
|
129
|
+
@ApiOperation({
|
130
|
+
summary: 'Create a new user',
|
131
|
+
description: 'Creates a new user with the provided data',
|
132
|
+
})
|
133
|
+
@ApiBody(
|
134
|
+
{
|
135
|
+
'application/json': {
|
136
|
+
schema: {
|
137
|
+
type: 'object',
|
138
|
+
required: ['name', 'email'],
|
139
|
+
properties: {
|
140
|
+
name: { type: 'string', example: 'John Doe' },
|
141
|
+
email: {
|
142
|
+
type: 'string',
|
143
|
+
format: 'email',
|
144
|
+
example: 'john@example.com'
|
145
|
+
},
|
146
|
+
},
|
147
|
+
},
|
148
|
+
},
|
149
|
+
},
|
150
|
+
{
|
151
|
+
description: 'User creation data',
|
152
|
+
required: true,
|
153
|
+
}
|
154
|
+
)
|
155
|
+
@ApiResponse('201', {
|
156
|
+
description: 'User created successfully',
|
157
|
+
content: {
|
158
|
+
'application/json': {
|
159
|
+
schema: {
|
160
|
+
type: 'object',
|
161
|
+
properties: {
|
162
|
+
id: { type: 'string' },
|
163
|
+
name: { type: 'string' },
|
164
|
+
email: { type: 'string' },
|
165
|
+
createdAt: { type: 'string', format: 'date-time' },
|
166
|
+
},
|
167
|
+
},
|
168
|
+
},
|
169
|
+
},
|
170
|
+
})
|
171
|
+
async createUser(@Body() userData: CreateUserDto) {
|
172
|
+
return this.usersService.create(userData);
|
173
|
+
}
|
174
|
+
```
|
175
|
+
|
176
|
+
### 🎨 可用装饰器
|
177
|
+
|
178
|
+
| 装饰器 | 用途 | 示例 |
|
179
|
+
|--------|------|------|
|
180
|
+
| `@ApiTags(...)` | 为控制器或方法添加标签 | `@ApiTags('Users', 'Admin')` |
|
181
|
+
| `@ApiOperation(...)` | 描述 API 操作 | `@ApiOperation({ summary: '获取用户' })` |
|
182
|
+
| `@ApiResponse(status, spec)` | 定义响应格式 | `@ApiResponse('200', { description: '成功' })` |
|
183
|
+
| `@ApiParam(name, spec)` | 描述路径参数 | `@ApiParam('id', { type: 'string' })` |
|
184
|
+
| `@ApiQuery(name, spec)` | 描述查询参数 | `@ApiQuery('page', { type: 'number' })` |
|
185
|
+
| `@ApiBody(schema, options)` | 描述请求体 | `@ApiBody({ schema: userSchema })` |
|
186
|
+
|
187
|
+
### ⚙️ 配置选项
|
188
|
+
|
189
|
+
```typescript
|
190
|
+
// 在 main.ts 中配置 API 文档
|
191
|
+
app.useScalarWithControllers(
|
192
|
+
[AppController, UsersController], // 需要生成文档的控制器
|
193
|
+
{
|
194
|
+
// OpenAPI 基本信息
|
195
|
+
info: {
|
196
|
+
title: 'HestJS Demo API',
|
197
|
+
version: '1.0.0',
|
198
|
+
description: 'HestJS 框架演示应用的 API 文档',
|
199
|
+
contact: {
|
200
|
+
name: 'API Support',
|
201
|
+
email: 'support@example.com',
|
202
|
+
},
|
203
|
+
license: {
|
204
|
+
name: 'MIT',
|
205
|
+
url: 'https://opensource.org/licenses/MIT',
|
206
|
+
},
|
207
|
+
},
|
208
|
+
// 服务器配置
|
209
|
+
servers: [
|
210
|
+
{
|
211
|
+
url: 'http://localhost:3002',
|
212
|
+
description: 'Development server',
|
213
|
+
},
|
214
|
+
{
|
215
|
+
url: 'https://api.example.com',
|
216
|
+
description: 'Production server',
|
217
|
+
},
|
218
|
+
],
|
219
|
+
},
|
220
|
+
{
|
221
|
+
// Scalar 配置
|
222
|
+
path: '/docs', // 文档访问路径
|
223
|
+
theme: 'elysia', // 主题样式
|
224
|
+
title: 'HestJS API Documentation', // 页面标题
|
225
|
+
enableMarkdown: true, // 启用 Markdown 导出
|
226
|
+
markdownPath: '/api-docs.md', // Markdown 访问路径
|
227
|
+
}
|
228
|
+
);
|
229
|
+
```
|
230
|
+
|
231
|
+
## 🏗️ 项目结构
|
232
|
+
|
233
|
+
```
|
234
|
+
src/
|
235
|
+
├── index.ts # 应用入口点
|
236
|
+
├── app.module.ts # 根模块
|
237
|
+
├── app.controller.ts # 应用控制器(含 API 文档注解示例)
|
238
|
+
├── app.service.ts # 应用服务
|
239
|
+
├── common/ # 公共组件
|
240
|
+
│ ├── filters/ # 全局过滤器
|
241
|
+
│ │ └── http-exception.filter.ts
|
242
|
+
│ └── interceptors/ # 全局拦截器
|
243
|
+
│ └── response.interceptor.ts
|
244
|
+
└── modules/ # 功能模块
|
245
|
+
├── users/ # 用户模块
|
246
|
+
│ ├── dto/ # 数据传输对象
|
247
|
+
│ │ └── user.dto.ts
|
248
|
+
│ ├── users.controller.ts # 用户控制器(含完整 API 注解)
|
249
|
+
│ ├── users.service.ts
|
250
|
+
│ └── users.module.ts
|
251
|
+
└── custom-validation/ # 自定义验证模块
|
252
|
+
├── dto/
|
253
|
+
│ └── custom-validation.dto.ts
|
254
|
+
├── custom-validation.controller.ts
|
255
|
+
├── custom-validation.service.ts
|
256
|
+
└── custom-validation.module.ts
|
257
|
+
```
|
258
|
+
|
259
|
+
## 🚀 快速开始
|
260
|
+
|
261
|
+
### 前置要求
|
262
|
+
|
263
|
+
- [Bun](https://bun.sh/) >= 1.0.0
|
264
|
+
- Node.js >= 18.0.0 (可选,Bun 包含 Node.js 兼容层)
|
265
|
+
|
266
|
+
### 安装依赖
|
267
|
+
|
268
|
+
```bash
|
269
|
+
bun install
|
270
|
+
```
|
271
|
+
|
272
|
+
### 开发环境
|
273
|
+
|
274
|
+
```bash
|
275
|
+
# 开发模式(热重载)
|
276
|
+
bun run dev
|
277
|
+
|
278
|
+
# 或者在 monorepo 根目录
|
279
|
+
turbo run dev --filter=@hestjs/demo
|
280
|
+
```
|
281
|
+
|
282
|
+
### 构建和部署
|
283
|
+
|
284
|
+
```bash
|
285
|
+
# 构建
|
286
|
+
bun run build
|
287
|
+
|
288
|
+
# 生产环境运行
|
289
|
+
bun run start:prod
|
290
|
+
|
291
|
+
# 创建独立可执行文件
|
292
|
+
bun run build:binary
|
293
|
+
./dist/hest-demo
|
294
|
+
```
|
295
|
+
|
296
|
+
## 📡 API 文档
|
297
|
+
|
298
|
+
### 基础端点
|
299
|
+
|
300
|
+
- `GET /api` - 应用信息
|
301
|
+
- `GET /api/health` - 健康检查
|
302
|
+
|
303
|
+
### 用户管理 (`/users`)
|
304
|
+
|
305
|
+
- `GET /users` - 获取所有用户
|
306
|
+
- `GET /users/:id` - 获取特定用户
|
307
|
+
- `POST /users` - 创建新用户
|
308
|
+
- `POST /users/:id` - 更新用户信息
|
309
|
+
|
310
|
+
#### 请求示例:
|
311
|
+
|
312
|
+
```bash
|
313
|
+
# 创建用户
|
314
|
+
curl -X POST http://localhost:3002/users \
|
315
|
+
-H "Content-Type: application/json" \
|
316
|
+
-d '{
|
317
|
+
"name": "John Doe",
|
318
|
+
"email": "john@example.com",
|
319
|
+
"age": 30,
|
320
|
+
"password": "password123"
|
321
|
+
}'
|
322
|
+
```
|
323
|
+
|
324
|
+
### 自定义验证 (`/api/custom`)
|
325
|
+
|
326
|
+
- `GET /api/custom` - 验证功能说明
|
327
|
+
- `POST /api/custom/validate` - 测试自定义验证
|
328
|
+
- `POST /api/custom/search` - 测试搜索参数验证
|
329
|
+
- `GET /api/custom/examples` - 获取验证示例
|
330
|
+
|
331
|
+
#### 请求示例:
|
332
|
+
|
333
|
+
```bash
|
334
|
+
# 自定义验证
|
335
|
+
curl -X POST http://localhost:3002/api/custom/validate \
|
336
|
+
-H "Content-Type: application/json" \
|
337
|
+
-d '{
|
338
|
+
"username": "john_doe123",
|
339
|
+
"role": "user",
|
340
|
+
"userId": "123e4567-e89b-12d3-a456-426614174000",
|
341
|
+
"phoneNumber": "13812345678",
|
342
|
+
"location": { "lat": 39.9042, "lng": 116.4074 },
|
343
|
+
"emails": ["john@example.com", "john.doe@company.com"]
|
344
|
+
}'
|
345
|
+
```
|
346
|
+
|
347
|
+
## 🛠️ 核心功能
|
348
|
+
|
349
|
+
### 1. 模块化架构
|
350
|
+
|
351
|
+
- **清晰的模块分离**:每个功能模块都有自己的控制器、服务、DTO 和实体
|
352
|
+
- **依赖注入**:使用 `@Injectable()` 和 `@Module()` 装饰器
|
353
|
+
- **模块导入/导出**:支持模块间的依赖关系
|
354
|
+
|
355
|
+
### 2. 强类型验证
|
356
|
+
|
357
|
+
- **TypeBox 集成**:使用 TypeBox 进行运行时类型验证
|
358
|
+
- **自定义验证器**:支持复杂的业务逻辑验证
|
359
|
+
- **联合类型支持**:支持 TypeScript 的高级类型特性
|
360
|
+
|
361
|
+
### 3. 中间件和拦截器
|
362
|
+
|
363
|
+
- **全局异常过滤器**:统一的错误处理
|
364
|
+
- **响应拦截器**:统一的响应格式
|
365
|
+
- **CORS 支持**:跨域资源共享配置
|
366
|
+
- **请求日志**:自动记录请求和响应
|
367
|
+
|
368
|
+
### 4. 配置管理
|
369
|
+
|
370
|
+
- **环境变量支持**:通过 `.env` 文件配置
|
371
|
+
- **类型安全配置**:使用 TypeScript 确保配置的类型安全
|
372
|
+
|
373
|
+
### 5. CQRS 支持
|
374
|
+
|
375
|
+
- **命令查询职责分离**:支持 CQRS 架构模式
|
376
|
+
- **事件驱动**:内置事件总线支持
|
377
|
+
- **命令和查询处理器**:独立的命令和查询处理逻辑
|
378
|
+
- **事件溯源**:支持事件驱动的业务逻辑
|
379
|
+
|
380
|
+
> 📝 **CQRS 演示应用**:完整的 CQRS 实现示例请参考 [HestJS CQRS Demo](https://github.com/aqz236/hestjs-cqrs-demo)
|
381
|
+
|
382
|
+
## 🔧 验证功能展示
|
383
|
+
|
384
|
+
### 基础验证
|
385
|
+
|
386
|
+
```typescript
|
387
|
+
export class CreateUserDto {
|
388
|
+
@IsString({ minLength: 2, maxLength: 50 })
|
389
|
+
name!: string;
|
390
|
+
|
391
|
+
@IsEmail()
|
392
|
+
email!: string;
|
393
|
+
|
394
|
+
@IsNumber()
|
395
|
+
@Min(0)
|
396
|
+
@Max(120)
|
397
|
+
age!: number;
|
398
|
+
}
|
399
|
+
```
|
400
|
+
|
401
|
+
### 高级验证
|
402
|
+
|
403
|
+
```typescript
|
404
|
+
export class CustomValidationDto {
|
405
|
+
// 正则表达式验证
|
406
|
+
@Custom(
|
407
|
+
Type.String({ minLength: 3, maxLength: 20, pattern: '^[a-zA-Z0-9_]+$' }),
|
408
|
+
{ message: '用户名必须是3-20位字母、数字或下划线' },
|
409
|
+
)
|
410
|
+
username!: string;
|
411
|
+
|
412
|
+
// 联合类型验证
|
413
|
+
@Custom(
|
414
|
+
Type.Union([
|
415
|
+
Type.Literal('admin'),
|
416
|
+
Type.Literal('user'),
|
417
|
+
Type.Literal('guest'),
|
418
|
+
]),
|
419
|
+
{ message: '角色必须是 admin、user 或 guest' },
|
420
|
+
)
|
421
|
+
role!: 'admin' | 'user' | 'guest';
|
422
|
+
|
423
|
+
// UUID 验证
|
424
|
+
@CommonValidators.UUID()
|
425
|
+
userId!: string;
|
426
|
+
|
427
|
+
// 中国手机号验证
|
428
|
+
@Custom(SchemaFactory.chinesePhoneNumber(), { optional: true })
|
429
|
+
phoneNumber?: string;
|
430
|
+
|
431
|
+
// 嵌套对象验证
|
432
|
+
@Custom(
|
433
|
+
Type.Object({
|
434
|
+
lat: Type.Number({ minimum: -90, maximum: 90 }),
|
435
|
+
lng: Type.Number({ minimum: -180, maximum: 180 }),
|
436
|
+
}),
|
437
|
+
{ optional: true },
|
438
|
+
)
|
439
|
+
location?: { lat: number; lng: number };
|
440
|
+
}
|
441
|
+
```
|
442
|
+
|
443
|
+
## 🎯 架构特点
|
444
|
+
|
445
|
+
### 1. NestJS 风格的目录结构
|
446
|
+
|
447
|
+
- 模块化组织:每个功能模块独立管理
|
448
|
+
- 清晰的职责分离:控制器、服务、DTO、实体分离
|
449
|
+
- 可扩展性:易于添加新功能模块
|
450
|
+
|
451
|
+
### 2. 现代 TypeScript 开发
|
452
|
+
|
453
|
+
- 严格的类型检查
|
454
|
+
- 装饰器模式
|
455
|
+
- 依赖注入
|
456
|
+
- 接口优先设计
|
457
|
+
|
458
|
+
### 3. 高性能运行时
|
459
|
+
|
460
|
+
- Bun 运行时支持
|
461
|
+
- Hono 高性能 Web 框架
|
462
|
+
- 端口复用优化
|
463
|
+
- 生产环境优化
|
464
|
+
|
465
|
+
### 4. CQRS 架构支持
|
466
|
+
|
467
|
+
- 命令查询职责分离模式
|
468
|
+
- 事件驱动架构
|
469
|
+
- 独立的读写模型
|
470
|
+
- 可扩展的处理器模式
|
471
|
+
|
472
|
+
> 🔗 **完整 CQRS 示例**:查看专门的 CQRS 演示应用 → [HestJS CQRS Demo](https://github.com/aqz236/hestjs-cqrs-demo)
|
473
|
+
|
474
|
+
## 📦 部署
|
475
|
+
|
476
|
+
### Docker 部署
|
477
|
+
|
478
|
+
```dockerfile
|
479
|
+
FROM oven/bun:1 as base
|
480
|
+
WORKDIR /app
|
481
|
+
|
482
|
+
# 复制依赖文件
|
483
|
+
COPY package.json bun.lock ./
|
484
|
+
RUN bun install --frozen-lockfile
|
485
|
+
|
486
|
+
# 复制源代码
|
487
|
+
COPY . .
|
488
|
+
|
489
|
+
# 构建应用
|
490
|
+
RUN bun run build
|
491
|
+
|
492
|
+
# 运行应用
|
493
|
+
CMD ["bun", "run", "start:prod"]
|
494
|
+
EXPOSE 3002
|
495
|
+
```
|
496
|
+
|
497
|
+
### 二进制部署
|
498
|
+
|
499
|
+
```bash
|
500
|
+
# 构建独立可执行文件
|
501
|
+
bun run build:binary
|
502
|
+
|
503
|
+
# 部署单个文件
|
504
|
+
./dist/hest-demo
|
505
|
+
```
|
506
|
+
|
507
|
+
## 🧪 测试
|
508
|
+
|
509
|
+
```bash
|
510
|
+
# 运行测试
|
511
|
+
bun test
|
512
|
+
|
513
|
+
# 覆盖率测试
|
514
|
+
bun test --coverage
|
515
|
+
```
|
516
|
+
|
517
|
+
## 📝 开发指南
|
518
|
+
|
519
|
+
### 添加新模块
|
520
|
+
|
521
|
+
1. 在 `src/modules/` 下创建新目录
|
522
|
+
2. 创建 `*.module.ts`、`*.controller.ts`、`*.service.ts`
|
523
|
+
3. 在 `app.module.ts` 中导入新模块
|
524
|
+
|
525
|
+
### 添加验证规则
|
526
|
+
|
527
|
+
1. 在模块的 `dto/` 目录下创建 DTO 类
|
528
|
+
2. 使用 `@Custom()` 装饰器定义验证规则
|
529
|
+
3. 在控制器中使用 `@Body()` 装饰器应用验证
|
530
|
+
|
531
|
+
### 环境配置
|
532
|
+
|
533
|
+
```bash
|
534
|
+
# .env 文件
|
535
|
+
PORT=3002
|
536
|
+
NODE_ENV=development
|
537
|
+
CORS_ORIGIN=*
|
538
|
+
```
|
539
|
+
|
540
|
+
## 🔗 相关项目
|
541
|
+
|
542
|
+
### HestJS CQRS Demo
|
543
|
+
|
544
|
+
完整的 CQRS(命令查询职责分离)架构演示应用,展示了如何在 HestJS 框架中实现:
|
545
|
+
|
546
|
+
- ✅ 命令处理器 (Command Handlers)
|
547
|
+
- ✅ 查询处理器 (Query Handlers)
|
548
|
+
- ✅ 事件处理器 (Event Handlers)
|
549
|
+
- ✅ 事件总线 (Event Bus)
|
550
|
+
- ✅ 用户管理完整流程
|
551
|
+
|
552
|
+
🔗 **仓库地址**:[https://github.com/aqz236/hestjs-cqrs-demo](https://github.com/aqz236/hestjs-cqrs-demo)
|
553
|
+
|
554
|
+
该项目展示了在现代 TypeScript 应用中如何优雅地实现 CQRS 模式,适合需要复杂业务逻辑和高可扩展性的企业级应用。
|
555
|
+
|
556
|
+
## 🤝 贡献
|
557
|
+
|
558
|
+
欢迎提交 Issue 和 Pull Request!
|
559
|
+
|
560
|
+
## 📄 许可证
|
561
|
+
|
562
|
+
MIT License
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import wfConfig from '@hestjs/eslint-config';
|
2
|
+
|
3
|
+
export default [
|
4
|
+
...wfConfig,
|
5
|
+
{
|
6
|
+
files: ['**/*.ts', '**/*.tsx'],
|
7
|
+
rules: {
|
8
|
+
'no-console': 'error', // Demo 应用允许使用 console 进行调试
|
9
|
+
},
|
10
|
+
},
|
11
|
+
{
|
12
|
+
// 忽略构建产物和临时文件
|
13
|
+
ignores: [
|
14
|
+
'node_modules/**',
|
15
|
+
'dist/**',
|
16
|
+
'build/**',
|
17
|
+
'*.d.ts',
|
18
|
+
'.bun/**',
|
19
|
+
'bun.lockb',
|
20
|
+
// shadcn 目录
|
21
|
+
'src/components/ui/**',
|
22
|
+
// scripts 目录
|
23
|
+
'scripts/**',
|
24
|
+
],
|
25
|
+
},
|
26
|
+
];
|
@@ -0,0 +1,62 @@
|
|
1
|
+
{
|
2
|
+
"name": "@hestjs/demo",
|
3
|
+
"version": "0.1.1",
|
4
|
+
"description": "HestJS Demo Application - A demonstration of HestJS framework capabilities",
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"types": "dist/index.d.ts",
|
7
|
+
"files": [
|
8
|
+
"dist",
|
9
|
+
"README.md"
|
10
|
+
],
|
11
|
+
"scripts": {
|
12
|
+
"dev": "bun run --hot src/index.ts",
|
13
|
+
"build": "bun build src/index.ts --outdir=dist --target=bun --format=esm --splitting --external pino --external pino-pretty --external sonic-boom --external thread-stream",
|
14
|
+
"build:external": "bun build src/index.ts --outdir=dist --target=bun --format=esm --external reflect-metadata --external pino --external pino-pretty --external sonic-boom --external thread-stream",
|
15
|
+
"build:binary": "bun build src/index.ts --compile --outfile=dist/hest-demo --external pino-pretty",
|
16
|
+
"start": "bun run dist/index.js | pino-pretty",
|
17
|
+
"start:binary": "./dist/hest-demo | pino-pretty",
|
18
|
+
"start:prod": "NODE_ENV=production bun run dist/index.js | pino-pretty",
|
19
|
+
"clean": "rm -rf dist",
|
20
|
+
"check-types": "tsc --noEmit"
|
21
|
+
},
|
22
|
+
"repository": {
|
23
|
+
"type": "git",
|
24
|
+
"url": "https://github.com/aqz236/hestjs-demo.git"
|
25
|
+
},
|
26
|
+
"homepage": "https://github.com/aqz236/hestjs-demo#readme",
|
27
|
+
"bugs": {
|
28
|
+
"url": "https://github.com/aqz236/hestjs-demo/issues"
|
29
|
+
},
|
30
|
+
"author": "aqz236",
|
31
|
+
"license": "MIT",
|
32
|
+
"dependencies": {
|
33
|
+
"@hestjs/core": "^0.1.8",
|
34
|
+
"@hestjs/logger": "^0.1.5",
|
35
|
+
"@hestjs/validation": "^0.1.5",
|
36
|
+
"hono": "^4.8.9",
|
37
|
+
"reflect-metadata": "^0.2.2"
|
38
|
+
},
|
39
|
+
"devDependencies": {
|
40
|
+
"@hestjs/eslint-config": "^0.1.1",
|
41
|
+
"@hestjs/typescript-config": "^0.1.0",
|
42
|
+
"@types/bun": "^1.2.19",
|
43
|
+
"jiti": "^2.5.1",
|
44
|
+
"typescript": "5.8.3"
|
45
|
+
},
|
46
|
+
"exports": {
|
47
|
+
".": {
|
48
|
+
"import": "./dist/index.js",
|
49
|
+
"require": "./dist/index.js",
|
50
|
+
"types": "./dist/index.d.ts"
|
51
|
+
}
|
52
|
+
},
|
53
|
+
"keywords": [
|
54
|
+
"hestjs",
|
55
|
+
"demo",
|
56
|
+
"framework",
|
57
|
+
"typescript",
|
58
|
+
"bun",
|
59
|
+
"hono",
|
60
|
+
"validation"
|
61
|
+
]
|
62
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Controller, Get, NotFoundException, Param, Post } from "@hestjs/core";
|
2
|
+
|
3
|
+
import { Body } from "@hestjs/validation";
|
4
|
+
import { AppService } from "./app.service";
|
5
|
+
import { CreateUserDto } from "./modules/users/dto/user.dto";
|
6
|
+
|
7
|
+
@Controller("/api")
|
8
|
+
export class AppController {
|
9
|
+
constructor(private readonly appService: AppService) {}
|
10
|
+
|
11
|
+
@Get("/")
|
12
|
+
getHello() {
|
13
|
+
return { message: this.appService.getHello() };
|
14
|
+
}
|
15
|
+
|
16
|
+
@Get("/users")
|
17
|
+
getUsers() {
|
18
|
+
return this.appService.getUsers();
|
19
|
+
}
|
20
|
+
|
21
|
+
@Get("/users/:id")
|
22
|
+
getUser(@Param("id") id: string) {
|
23
|
+
const user = this.appService.getUser(id);
|
24
|
+
if (!user) {
|
25
|
+
throw new NotFoundException(`User with id ${id} not found`);
|
26
|
+
}
|
27
|
+
return user;
|
28
|
+
}
|
29
|
+
|
30
|
+
@Post("/users")
|
31
|
+
createUser(@Body(CreateUserDto) createUserDto: CreateUserDto) {
|
32
|
+
return this.appService.createUser(createUserDto);
|
33
|
+
}
|
34
|
+
|
35
|
+
@Get("/error")
|
36
|
+
throwError() {
|
37
|
+
throw new Error("This is a test error");
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Module } from '@hestjs/core';
|
2
|
+
import { AppController } from './app.controller';
|
3
|
+
import { AppService } from './app.service';
|
4
|
+
import { UsersModule } from './modules/users/users.module';
|
5
|
+
import { CustomValidationModule } from './modules/custom-validation/custom-validation.module';
|
6
|
+
|
7
|
+
@Module({
|
8
|
+
imports: [UsersModule, CustomValidationModule],
|
9
|
+
controllers: [AppController],
|
10
|
+
providers: [AppService],
|
11
|
+
})
|
12
|
+
export class AppModule {}
|