create-hest-app 0.1.0 → 0.1.2
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/dist/index.js +74 -81
- package/package.json +1 -1
- package/templates/base/README.md +11 -11
- package/templates/base/eslint.config.ts +0 -2
- package/templates/base/package.json +1 -1
- package/templates/base_scalar/README.md +11 -11
- package/templates/base_scalar/eslint.config.ts +0 -2
- package/templates/base_scalar/package.json +2 -2
- package/templates/base_scalar/src/index.ts +2 -3
- package/templates/cqrs/eslint.config.ts +0 -2
- package/templates/cqrs/package.json +2 -2
- package/templates/cqrs_scalar/bun.lock +1196 -0
- package/templates/cqrs_scalar/eslint.config.ts +0 -2
- package/templates/cqrs_scalar/package.json +3 -2
- package/templates/cqrs_scalar/src/app.controller.ts +64 -1
- package/templates/cqrs_scalar/src/app.module.ts +2 -2
- package/templates/cqrs_scalar/src/common/interceptors/response.interceptor.ts +2 -3
- package/templates/cqrs_scalar/src/index.ts +56 -2
- package/templates/cqrs_scalar/src/users/repositories/user.repository.ts +40 -1
- package/templates/cqrs_scalar/src/users/user.controller.ts +245 -6
@@ -30,9 +30,10 @@
|
|
30
30
|
"author": "aqz236",
|
31
31
|
"license": "MIT",
|
32
32
|
"dependencies": {
|
33
|
-
"@hestjs/core": "^0.1.
|
33
|
+
"@hestjs/core": "^0.1.9",
|
34
34
|
"@hestjs/validation": "^0.1.5",
|
35
|
-
"@hestjs/cqrs": "^0.1.
|
35
|
+
"@hestjs/cqrs": "^0.1.3",
|
36
|
+
"@hestjs/scalar": "^0.1.4",
|
36
37
|
"hono": "^4.8.9",
|
37
38
|
"reflect-metadata": "^0.2.2"
|
38
39
|
},
|
@@ -1,15 +1,58 @@
|
|
1
1
|
import { Controller, Get } from '@hestjs/core';
|
2
|
+
import { ApiOperation, ApiResponse, ApiTags } from '@hestjs/scalar';
|
2
3
|
import { AppService } from './app.service';
|
3
4
|
|
4
5
|
@Controller('/')
|
6
|
+
@ApiTags('Application')
|
5
7
|
export class AppController {
|
6
8
|
constructor(private readonly appService: AppService) {}
|
7
9
|
|
8
10
|
@Get('/')
|
11
|
+
@ApiOperation({
|
12
|
+
summary: 'Get application info',
|
13
|
+
description: 'Returns application information and available endpoints',
|
14
|
+
tags: ['Health Check', 'Application'],
|
15
|
+
})
|
16
|
+
@ApiResponse('200', {
|
17
|
+
description: 'Application information',
|
18
|
+
content: {
|
19
|
+
'application/json': {
|
20
|
+
schema: {
|
21
|
+
type: 'object',
|
22
|
+
properties: {
|
23
|
+
message: {
|
24
|
+
type: 'string',
|
25
|
+
example: 'Hello World from HestJS CQRS!',
|
26
|
+
},
|
27
|
+
description: {
|
28
|
+
type: 'string',
|
29
|
+
example:
|
30
|
+
'HestJS CQRS Demo - A demonstration of CQRS pattern using HestJS framework',
|
31
|
+
},
|
32
|
+
endpoints: {
|
33
|
+
type: 'object',
|
34
|
+
properties: {
|
35
|
+
users: {
|
36
|
+
type: 'object',
|
37
|
+
properties: {
|
38
|
+
getAll: { type: 'string', example: 'GET /users' },
|
39
|
+
getById: { type: 'string', example: 'GET /users/:id' },
|
40
|
+
create: { type: 'string', example: 'POST /users' },
|
41
|
+
update: { type: 'string', example: 'PUT /users/:id' },
|
42
|
+
},
|
43
|
+
},
|
44
|
+
},
|
45
|
+
},
|
46
|
+
},
|
47
|
+
},
|
48
|
+
},
|
49
|
+
},
|
50
|
+
})
|
9
51
|
getHello() {
|
10
52
|
return {
|
11
53
|
message: this.appService.getHello(),
|
12
|
-
description:
|
54
|
+
description:
|
55
|
+
'HestJS CQRS Demo - A demonstration of CQRS pattern using HestJS framework',
|
13
56
|
endpoints: {
|
14
57
|
users: {
|
15
58
|
getAll: 'GET /users',
|
@@ -22,6 +65,26 @@ export class AppController {
|
|
22
65
|
}
|
23
66
|
|
24
67
|
@Get('/error')
|
68
|
+
@ApiOperation({
|
69
|
+
summary: 'Test error endpoint',
|
70
|
+
description: 'Throws an error for testing exception handling and filters',
|
71
|
+
})
|
72
|
+
@ApiResponse('500', {
|
73
|
+
description: 'Internal server error',
|
74
|
+
content: {
|
75
|
+
'application/json': {
|
76
|
+
schema: {
|
77
|
+
type: 'object',
|
78
|
+
properties: {
|
79
|
+
message: {
|
80
|
+
type: 'string',
|
81
|
+
example: 'This is a test error for exception handling',
|
82
|
+
},
|
83
|
+
},
|
84
|
+
},
|
85
|
+
},
|
86
|
+
},
|
87
|
+
})
|
25
88
|
throwError() {
|
26
89
|
throw new Error('This is a test error for exception handling');
|
27
90
|
}
|
@@ -2,11 +2,11 @@ import { Module } from '@hestjs/core';
|
|
2
2
|
import { CqrsModule } from '@hestjs/cqrs';
|
3
3
|
import { AppController } from './app.controller';
|
4
4
|
import { AppService } from './app.service';
|
5
|
-
import { UserModule } from './users';
|
5
|
+
import { UserController, UserModule } from './users';
|
6
6
|
|
7
7
|
@Module({
|
8
8
|
imports: [CqrsModule.forRoot(), UserModule],
|
9
|
-
controllers: [AppController],
|
9
|
+
controllers: [AppController, UserController],
|
10
10
|
providers: [AppService],
|
11
11
|
})
|
12
12
|
export class AppModule {}
|
@@ -19,13 +19,12 @@ export class ResponseInterceptor implements Interceptor {
|
|
19
19
|
const startTime = Date.now();
|
20
20
|
const request = context.switchToHttp().getRequest();
|
21
21
|
|
22
|
-
logger.info(`🚀 Request: ${request.method} ${request.url}`);
|
23
22
|
|
24
23
|
const result = await next.handle();
|
25
|
-
|
24
|
+
|
26
25
|
const duration = Date.now() - startTime;
|
27
26
|
logger.info(
|
28
|
-
|
27
|
+
`🚀 Response: ${request.method} ${request.url} - ${duration}ms`,
|
29
28
|
);
|
30
29
|
|
31
30
|
return {
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { HestFactory, logger } from '@hestjs/core';
|
2
|
+
import '@hestjs/scalar'; // 导入scalar扩展
|
2
3
|
import { ValidationInterceptor } from '@hestjs/validation';
|
3
4
|
import { cors } from 'hono/cors';
|
4
|
-
import { logger as log } from 'hono/logger';
|
5
5
|
import { AppModule } from './app.module';
|
6
6
|
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
|
7
7
|
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
|
@@ -12,7 +12,7 @@ async function bootstrap() {
|
|
12
12
|
|
13
13
|
const app = await HestFactory.create(AppModule);
|
14
14
|
app.hono().use(cors()); // 使用 Hono 的 CORS 中间件
|
15
|
-
app.hono().use('*', log()); // 使用 Hono 的日志中间件
|
15
|
+
// app.hono().use('*', log()); // 使用 Hono 的日志中间件
|
16
16
|
|
17
17
|
// 全局拦截器 - 验证拦截器应该在响应拦截器之前
|
18
18
|
app.useGlobalInterceptors(new ValidationInterceptor());
|
@@ -21,6 +21,60 @@ async function bootstrap() {
|
|
21
21
|
// 全局异常过滤器
|
22
22
|
app.useGlobalFilters(new HttpExceptionFilter());
|
23
23
|
|
24
|
+
// 设置OpenAPI规范端点
|
25
|
+
app.useSwagger(
|
26
|
+
{
|
27
|
+
info: {
|
28
|
+
title: 'HestJS CQRS Demo API',
|
29
|
+
version: '1.0.0',
|
30
|
+
description:
|
31
|
+
'A demonstration of HestJS CQRS framework capabilities with Scalar API documentation (Auto-discovered controllers)',
|
32
|
+
},
|
33
|
+
servers: [
|
34
|
+
{
|
35
|
+
url: 'http://localhost:3002',
|
36
|
+
description: 'Development server',
|
37
|
+
},
|
38
|
+
],
|
39
|
+
},
|
40
|
+
{
|
41
|
+
path: '/docs',
|
42
|
+
theme: 'elysia', // 使用elysia主题
|
43
|
+
enableMarkdown: true,
|
44
|
+
markdownPath: '/api-docs.md',
|
45
|
+
},
|
46
|
+
);
|
47
|
+
|
48
|
+
// 可选:仍然支持手动指定控制器的方式
|
49
|
+
// app.useScalarWithControllers(
|
50
|
+
// [AppController, UserController], // 传入需要生成文档的控制器
|
51
|
+
// {
|
52
|
+
// info: {
|
53
|
+
// title: 'HestJS CQRS Demo API',
|
54
|
+
// version: '1.0.0',
|
55
|
+
// description:
|
56
|
+
// 'A demonstration of HestJS CQRS framework capabilities with Scalar API documentation',
|
57
|
+
// },
|
58
|
+
// servers: [
|
59
|
+
// {
|
60
|
+
// url: 'http://localhost:3002',
|
61
|
+
// description: 'Development server',
|
62
|
+
// },
|
63
|
+
// ],
|
64
|
+
// },
|
65
|
+
// {
|
66
|
+
// path: '/docs',
|
67
|
+
// theme: 'elysia', // 使用elysia主题
|
68
|
+
// enableMarkdown: true,
|
69
|
+
// markdownPath: '/api-docs.md',
|
70
|
+
// },
|
71
|
+
// );
|
72
|
+
|
73
|
+
logger.info('📚 API Documentation available at:');
|
74
|
+
logger.info(' • Scalar UI: http://localhost:3002/docs');
|
75
|
+
logger.info(' • OpenAPI JSON: http://localhost:3002/openapi.json');
|
76
|
+
logger.info(' • Markdown (for LLMs): http://localhost:3002/api-docs.md');
|
77
|
+
|
24
78
|
const server = Bun.serve({
|
25
79
|
port: 3002,
|
26
80
|
fetch: app.hono().fetch,
|
@@ -4,7 +4,46 @@ import { User, CreateUserData, UpdateUserData } from '../entities';
|
|
4
4
|
@Injectable()
|
5
5
|
export class UserRepository {
|
6
6
|
private users: Map<string, User> = new Map();
|
7
|
-
private nextId =
|
7
|
+
private nextId = 4; // 从4开始,因为我们预填充了3个用户
|
8
|
+
|
9
|
+
constructor() {
|
10
|
+
// 初始化一些 mock 数据
|
11
|
+
this.initializeMockData();
|
12
|
+
}
|
13
|
+
|
14
|
+
private initializeMockData() {
|
15
|
+
const mockUsers: User[] = [
|
16
|
+
{
|
17
|
+
id: '1',
|
18
|
+
name: 'Alice Johnson',
|
19
|
+
email: 'alice@example.com',
|
20
|
+
age: 28,
|
21
|
+
createdAt: new Date('2024-01-15T08:30:00Z'),
|
22
|
+
updatedAt: new Date('2024-01-15T08:30:00Z'),
|
23
|
+
},
|
24
|
+
{
|
25
|
+
id: '2',
|
26
|
+
name: 'Bob Smith',
|
27
|
+
email: 'bob@example.com',
|
28
|
+
age: 32,
|
29
|
+
createdAt: new Date('2024-01-16T10:15:00Z'),
|
30
|
+
updatedAt: new Date('2024-01-16T10:15:00Z'),
|
31
|
+
},
|
32
|
+
{
|
33
|
+
id: '3',
|
34
|
+
name: 'Charlie Brown',
|
35
|
+
email: 'charlie@example.com',
|
36
|
+
age: 25,
|
37
|
+
createdAt: new Date('2024-01-17T14:20:00Z'),
|
38
|
+
updatedAt: new Date('2024-01-17T14:20:00Z'),
|
39
|
+
},
|
40
|
+
];
|
41
|
+
|
42
|
+
// 将 mock 数据添加到内存存储中
|
43
|
+
mockUsers.forEach(user => {
|
44
|
+
this.users.set(user.id, user);
|
45
|
+
});
|
46
|
+
}
|
8
47
|
|
9
48
|
async create(userData: CreateUserData): Promise<User> {
|
10
49
|
const id = this.nextId.toString();
|
@@ -1,11 +1,19 @@
|
|
1
|
-
import { Controller, Get, Post, Put, Context } from '@hestjs/core';
|
2
1
|
import type { HestContext } from '@hestjs/core';
|
2
|
+
import { Context, Controller, Get, Post, Put } from '@hestjs/core';
|
3
3
|
import { CommandBus, QueryBus } from '@hestjs/cqrs';
|
4
|
+
import {
|
5
|
+
ApiBody,
|
6
|
+
ApiOperation,
|
7
|
+
ApiParam,
|
8
|
+
ApiResponse,
|
9
|
+
ApiTags,
|
10
|
+
} from '@hestjs/scalar';
|
4
11
|
import { CreateUserCommand, UpdateUserCommand } from './commands';
|
5
12
|
import { CreateUserData, UpdateUserData } from './entities';
|
6
13
|
import { GetAllUsersQuery, GetUserQuery } from './queries';
|
7
14
|
|
8
15
|
@Controller('/users')
|
16
|
+
@ApiTags('Users')
|
9
17
|
export class UserController {
|
10
18
|
constructor(
|
11
19
|
private readonly commandBus: CommandBus,
|
@@ -13,6 +21,85 @@ export class UserController {
|
|
13
21
|
) {}
|
14
22
|
|
15
23
|
@Post('/')
|
24
|
+
@ApiOperation({
|
25
|
+
summary: 'Create a new user',
|
26
|
+
description: 'Creates a new user using CQRS pattern with command bus',
|
27
|
+
})
|
28
|
+
@ApiBody(
|
29
|
+
{
|
30
|
+
'application/json': {
|
31
|
+
schema: {
|
32
|
+
type: 'object',
|
33
|
+
required: ['name', 'email'],
|
34
|
+
properties: {
|
35
|
+
name: {
|
36
|
+
type: 'string',
|
37
|
+
example: 'John Doe',
|
38
|
+
description: 'User full name',
|
39
|
+
},
|
40
|
+
email: {
|
41
|
+
type: 'string',
|
42
|
+
format: 'email',
|
43
|
+
example: 'john@example.com',
|
44
|
+
description: 'User email address',
|
45
|
+
},
|
46
|
+
age: {
|
47
|
+
type: 'number',
|
48
|
+
example: 25,
|
49
|
+
description: 'User age (optional)',
|
50
|
+
minimum: 0,
|
51
|
+
maximum: 150,
|
52
|
+
},
|
53
|
+
},
|
54
|
+
},
|
55
|
+
},
|
56
|
+
},
|
57
|
+
{
|
58
|
+
description: 'User creation data',
|
59
|
+
required: true,
|
60
|
+
},
|
61
|
+
)
|
62
|
+
@ApiResponse('201', {
|
63
|
+
description: 'User created successfully',
|
64
|
+
content: {
|
65
|
+
'application/json': {
|
66
|
+
schema: {
|
67
|
+
type: 'object',
|
68
|
+
properties: {
|
69
|
+
success: { type: 'boolean', example: true },
|
70
|
+
data: {
|
71
|
+
type: 'object',
|
72
|
+
properties: {
|
73
|
+
id: { type: 'string', example: '1' },
|
74
|
+
name: { type: 'string', example: 'John Doe' },
|
75
|
+
email: { type: 'string', example: 'john@example.com' },
|
76
|
+
age: { type: 'number', example: 25 },
|
77
|
+
createdAt: { type: 'string', format: 'date-time' },
|
78
|
+
updatedAt: { type: 'string', format: 'date-time' },
|
79
|
+
},
|
80
|
+
},
|
81
|
+
},
|
82
|
+
},
|
83
|
+
},
|
84
|
+
},
|
85
|
+
})
|
86
|
+
@ApiResponse('400', {
|
87
|
+
description: 'Invalid input data',
|
88
|
+
content: {
|
89
|
+
'application/json': {
|
90
|
+
schema: {
|
91
|
+
type: 'object',
|
92
|
+
properties: {
|
93
|
+
success: { type: 'boolean', example: false },
|
94
|
+
error: {
|
95
|
+
type: 'string',
|
96
|
+
example: 'Name and email are required',
|
97
|
+
},
|
98
|
+
},
|
99
|
+
},
|
100
|
+
},
|
101
|
+
},
|
102
|
+
})
|
16
103
|
async createUser(@Context() c: HestContext) {
|
17
104
|
const userData = await c.req.json<CreateUserData>();
|
18
105
|
|
@@ -25,16 +112,69 @@ export class UserController {
|
|
25
112
|
}
|
26
113
|
|
27
114
|
const user = await this.commandBus.execute(new CreateUserCommand(userData));
|
28
|
-
|
115
|
+
// 直接返回数据,让拦截器处理响应格式
|
116
|
+
// 注意:这里我们无法通过拦截器设置状态码为201,如果需要可以抛出特殊异常或使用其他方式
|
117
|
+
return user;
|
29
118
|
}
|
30
119
|
|
31
120
|
@Get('/')
|
32
|
-
async getAllUsers(
|
121
|
+
async getAllUsers() {
|
122
|
+
|
123
|
+
// 使用查询总线获取所有用户
|
33
124
|
const result = await this.queryBus.execute(new GetAllUsersQuery());
|
34
|
-
|
125
|
+
|
126
|
+
// 直接返回数据,让拦截器处理响应格式
|
127
|
+
return result.users;
|
35
128
|
}
|
36
129
|
|
37
130
|
@Get('/:id')
|
131
|
+
@ApiOperation({
|
132
|
+
summary: 'Get user by ID',
|
133
|
+
description: 'Retrieves a specific user by their ID using CQRS pattern',
|
134
|
+
})
|
135
|
+
@ApiParam('id', {
|
136
|
+
description: 'User unique identifier',
|
137
|
+
schema: { type: 'string' },
|
138
|
+
example: '1',
|
139
|
+
})
|
140
|
+
@ApiResponse('200', {
|
141
|
+
description: 'User found successfully',
|
142
|
+
content: {
|
143
|
+
'application/json': {
|
144
|
+
schema: {
|
145
|
+
type: 'object',
|
146
|
+
properties: {
|
147
|
+
success: { type: 'boolean', example: true },
|
148
|
+
data: {
|
149
|
+
type: 'object',
|
150
|
+
properties: {
|
151
|
+
id: { type: 'string', example: '1' },
|
152
|
+
name: { type: 'string', example: 'John Doe' },
|
153
|
+
email: { type: 'string', example: 'john@example.com' },
|
154
|
+
age: { type: 'number', example: 25 },
|
155
|
+
createdAt: { type: 'string', format: 'date-time' },
|
156
|
+
updatedAt: { type: 'string', format: 'date-time' },
|
157
|
+
},
|
158
|
+
},
|
159
|
+
},
|
160
|
+
},
|
161
|
+
},
|
162
|
+
},
|
163
|
+
})
|
164
|
+
@ApiResponse('404', {
|
165
|
+
description: 'User not found',
|
166
|
+
content: {
|
167
|
+
'application/json': {
|
168
|
+
schema: {
|
169
|
+
type: 'object',
|
170
|
+
properties: {
|
171
|
+
success: { type: 'boolean', example: false },
|
172
|
+
error: { type: 'string', example: 'User not found' },
|
173
|
+
},
|
174
|
+
},
|
175
|
+
},
|
176
|
+
},
|
177
|
+
})
|
38
178
|
async getUserById(@Context() c: HestContext) {
|
39
179
|
const id = c.req.param('id');
|
40
180
|
const result = await this.queryBus.execute(new GetUserQuery(id));
|
@@ -43,10 +183,108 @@ export class UserController {
|
|
43
183
|
return c.json({ success: false, error: 'User not found' }, 404);
|
44
184
|
}
|
45
185
|
|
46
|
-
|
186
|
+
// 直接返回数据,让拦截器处理响应格式
|
187
|
+
return result.user;
|
47
188
|
}
|
48
189
|
|
49
190
|
@Put('/:id')
|
191
|
+
@ApiOperation({
|
192
|
+
summary: 'Update user by ID',
|
193
|
+
description: 'Updates an existing user using CQRS pattern with command bus',
|
194
|
+
})
|
195
|
+
@ApiParam('id', {
|
196
|
+
description: 'User unique identifier',
|
197
|
+
schema: { type: 'string' },
|
198
|
+
example: '1',
|
199
|
+
})
|
200
|
+
@ApiBody(
|
201
|
+
{
|
202
|
+
'application/json': {
|
203
|
+
schema: {
|
204
|
+
type: 'object',
|
205
|
+
properties: {
|
206
|
+
name: {
|
207
|
+
type: 'string',
|
208
|
+
example: 'Jane Doe',
|
209
|
+
description: 'User full name (optional)',
|
210
|
+
},
|
211
|
+
email: {
|
212
|
+
type: 'string',
|
213
|
+
format: 'email',
|
214
|
+
example: 'jane@example.com',
|
215
|
+
description: 'User email address (optional)',
|
216
|
+
},
|
217
|
+
age: {
|
218
|
+
type: 'number',
|
219
|
+
example: 30,
|
220
|
+
description: 'User age (optional)',
|
221
|
+
minimum: 0,
|
222
|
+
maximum: 150,
|
223
|
+
},
|
224
|
+
},
|
225
|
+
},
|
226
|
+
},
|
227
|
+
},
|
228
|
+
{
|
229
|
+
description: 'User update data (all fields are optional)',
|
230
|
+
required: true,
|
231
|
+
},
|
232
|
+
)
|
233
|
+
@ApiResponse('200', {
|
234
|
+
description: 'User updated successfully',
|
235
|
+
content: {
|
236
|
+
'application/json': {
|
237
|
+
schema: {
|
238
|
+
type: 'object',
|
239
|
+
properties: {
|
240
|
+
success: { type: 'boolean', example: true },
|
241
|
+
data: {
|
242
|
+
type: 'object',
|
243
|
+
properties: {
|
244
|
+
id: { type: 'string', example: '1' },
|
245
|
+
name: { type: 'string', example: 'Jane Doe' },
|
246
|
+
email: { type: 'string', example: 'jane@example.com' },
|
247
|
+
age: { type: 'number', example: 30 },
|
248
|
+
createdAt: { type: 'string', format: 'date-time' },
|
249
|
+
updatedAt: { type: 'string', format: 'date-time' },
|
250
|
+
},
|
251
|
+
},
|
252
|
+
},
|
253
|
+
},
|
254
|
+
},
|
255
|
+
},
|
256
|
+
})
|
257
|
+
@ApiResponse('404', {
|
258
|
+
description: 'User not found',
|
259
|
+
content: {
|
260
|
+
'application/json': {
|
261
|
+
schema: {
|
262
|
+
type: 'object',
|
263
|
+
properties: {
|
264
|
+
success: { type: 'boolean', example: false },
|
265
|
+
error: { type: 'string', example: 'User not found' },
|
266
|
+
},
|
267
|
+
},
|
268
|
+
},
|
269
|
+
},
|
270
|
+
})
|
271
|
+
@ApiResponse('500', {
|
272
|
+
description: 'Internal server error',
|
273
|
+
content: {
|
274
|
+
'application/json': {
|
275
|
+
schema: {
|
276
|
+
type: 'object',
|
277
|
+
properties: {
|
278
|
+
success: { type: 'boolean', example: false },
|
279
|
+
error: {
|
280
|
+
type: 'string',
|
281
|
+
example: 'An error occurred while updating the user',
|
282
|
+
},
|
283
|
+
},
|
284
|
+
},
|
285
|
+
},
|
286
|
+
},
|
287
|
+
})
|
50
288
|
async updateUser(@Context() c: HestContext) {
|
51
289
|
const id = c.req.param('id');
|
52
290
|
const userData = await c.req.json<UpdateUserData>();
|
@@ -55,7 +293,8 @@ export class UserController {
|
|
55
293
|
const user = await this.commandBus.execute(
|
56
294
|
new UpdateUserCommand(id, userData),
|
57
295
|
);
|
58
|
-
|
296
|
+
// 直接返回数据,让拦截器处理响应格式
|
297
|
+
return user;
|
59
298
|
} catch (error) {
|
60
299
|
if (error instanceof Error && error.message.includes('not found')) {
|
61
300
|
return c.json({ success: false, error: 'User not found' }, 404);
|