koa3-cli 1.0.5 → 1.0.7

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/public/index.html CHANGED
@@ -69,6 +69,10 @@
69
69
  <h3>✅ 错误处理</h3>
70
70
  <p>统一的错误处理机制</p>
71
71
  </div>
72
+ <div class="feature">
73
+ <h3>📝 日志系统</h3>
74
+ <p>支持访问日志、错误日志和 requestId 链路追踪</p>
75
+ </div>
72
76
  <div class="feature">
73
77
  <h3>⚡ CLI 工具</h3>
74
78
  <p>一键创建项目,快速上手</p>
@@ -144,7 +148,14 @@ npm run dev</code></pre>
144
148
  │ │ └── user.js # 用户模型
145
149
  │ ├── middleware/ # 中间件目录
146
150
  │ │ ├── index.js # 中间件入口
147
- │ │ └── auth.js # 认证中间件示例
151
+ │ │ ├── auth.js # 认证中间件示例
152
+ │ │ ├── requestLogger.js # 请求日志中间件
153
+ │ │ └── errorHandler.js # 全局错误处理
154
+ │ ├── lib/ # 基础能力目录
155
+ │ │ ├── logger.js # 日志工具
156
+ │ │ └── validator.js # 参数校验中间件(Joi)
157
+ │ ├── schema/ # 参数校验规则目录
158
+ │ │ └── user.js # 用户相关校验规则
148
159
  │ ├── router.js # 路由配置
149
160
  │ └── view/ # 视图模板目录(可选)
150
161
  │ └── docs.ejs # 页面模板
@@ -157,6 +168,7 @@ npm run dev</code></pre>
157
168
  ├── public/ # 静态资源目录
158
169
  │ ├── docs/ # 文档资源
159
170
  │ └── index.html # 文档首页
171
+ ├── logs/ # 日志目录(运行时自动创建)
160
172
  ├── app.js # 应用入口文件
161
173
  ├── package.json # 项目配置
162
174
  ├── env.example # 环境变量示例
@@ -237,7 +249,16 @@ REDIS_PASSWORD=
237
249
  REDIS_DB=0
238
250
 
239
251
  # 日志级别
240
- LOG_LEVEL=info</code></pre>
252
+ LOG_LEVEL=info
253
+
254
+ # 日志目录
255
+ LOG_DIR=logs
256
+
257
+ # 是否输出到控制台
258
+ LOG_ENABLE_CONSOLE=true
259
+
260
+ # 是否输出到文件
261
+ LOG_ENABLE_FILE=true</code></pre>
241
262
  <h2>配置项说明</h2>
242
263
  <h3>基础配置</h3>
243
264
  <pre><code class="language-javascript">{
@@ -288,11 +309,26 @@ LOG_LEVEL=info</code></pre>
288
309
  password: '',
289
310
  db: 0
290
311
  }</code></pre>
291
- <h3>日志配置</h3>
292
- <pre><code class="language-javascript">logger: {
312
+ <h3>日志配置</h3>
313
+ <pre><code class="language-javascript">logger: {
293
314
  level: 'info', // 日志级别: debug, info, warn, error
294
- dir: 'logs' // 日志目录
315
+ dir: 'logs', // 日志目录
316
+ enableConsole: true, // 是否输出到控制台
317
+ enableFile: true // 是否输出到文件
295
318
  }</code></pre>
319
+ <h3>日志文件说明</h3>
320
+ <ul>
321
+ <li><code>YYYY-MM-DD.log</code>: 通用应用日志</li>
322
+ <li><code>YYYY-MM-DD.access.log</code>: 请求访问日志(JSON 行格式)</li>
323
+ <li><code>YYYY-MM-DD.error.log</code>: 错误级别日志</li>
324
+ </ul>
325
+ <h3>请求追踪(x-request-id)</h3>
326
+ <p>每个请求都会自动记录 <code>requestId</code>:</p>
327
+ <ul>
328
+ <li>请求头带有 <code>x-request-id</code> 时会透传该值</li>
329
+ <li>未提供时服务端会自动生成并在响应头返回</li>
330
+ <li>访问日志与错误日志都会带上 <code>requestId</code>,便于串联排查</li>
331
+ </ul>
296
332
  </div>
297
333
 
298
334
  <!-- 开发指南 -->
@@ -390,6 +426,15 @@ module.exports = async (ctx, next) => {
390
426
  await logger(ctx, next);
391
427
  // 其他中间件...
392
428
  };</code></pre>
429
+ <h2>添加参数校验</h2>
430
+ <p>使用 Joi 在路由上挂载 <code>validate(schemas)</code>,按需校验 <code>body</code>、<code>query</code>、<code>params</code>。校验通过后从 <code>ctx.state.validated</code> 读取数据。</p>
431
+ <pre><code class="language-javascript">const { validate } = require('./lib/validator');
432
+ const userSchema = require('./schema/user');
433
+
434
+ router.get('/api/user/:id', validate({ params: userSchema.idParam }), userController.detail);
435
+ router.post('/api/user', validate({ body: userSchema.createUserBody }), userController.create);
436
+ router.put('/api/user/:id', validate({ params: userSchema.idParam, body: userSchema.updateUserBody }), userController.update);</code></pre>
437
+ <p>校验规则定义在 <code>app/schema/</code> 下(如 <code>user.js</code>),使用 Joi 编写,支持 <code>.messages()</code> 自定义提示。校验未通过时返回 422,<code>message</code> 为第一条未通过项的提示,<code>errors</code> 为全部校验项。</p>
393
438
  <h2>错误处理</h2>
394
439
  <p>控制器中的错误会自动被错误处理中间件捕获:</p>
395
440
  <pre><code class="language-javascript">// 抛出错误
@@ -397,11 +442,19 @@ ctx.throw(400, 'Bad Request');
397
442
 
398
443
  // 或者
399
444
  throw new Error('Something went wrong');</code></pre>
400
- <p>错误会被统一处理并返回:</p>
445
+ <p>错误会被统一处理并返回。普通错误:</p>
401
446
  <pre><code class="language-json">{
402
447
  "success": false,
403
448
  "message": "Error message",
404
449
  "stack": "..." // 仅在开发环境显示
450
+ }</code></pre>
451
+ <p>参数校验失败(422)时,<code>message</code> 为第一条校验提示,<code>errors</code> 为所有校验项:</p>
452
+ <pre><code class="language-json">{
453
+ "success": false,
454
+ "message": "用户名为必填",
455
+ "errors": [
456
+ { "field": "name", "message": "用户名为必填" }
457
+ ]
405
458
  }</code></pre>
406
459
  <h2>响应格式</h2>
407
460
  <p>API 请求会自动统一响应格式:</p>
@@ -437,6 +490,15 @@ throw new Error('Something went wrong');</code></pre>
437
490
  "success": false,
438
491
  "message": "错误信息",
439
492
  "stack": "..." // 仅在开发环境显示
493
+ }</code></pre>
494
+ <h3>参数校验失败(422)</h3>
495
+ <p><code>message</code> 为第一条未通过项的提示,<code>errors</code> 为全部校验项:</p>
496
+ <pre><code class="language-json">{
497
+ "success": false,
498
+ "message": "用户名为必填",
499
+ "errors": [
500
+ { "field": "name", "message": "用户名为必填" }
501
+ ]
440
502
  }</code></pre>
441
503
  <h2>API 列表</h2>
442
504
  <ul>
@@ -471,7 +533,7 @@ throw new Error('Something went wrong');</code></pre>
471
533
  ]
472
534
  }</code></pre>
473
535
  <h2>获取用户详情</h2>
474
- <p>根据用户 ID 获取用户详情。</p>
536
+ <p>根据用户 ID 获取用户详情。路径参数 <code>id</code> 会经过 Joi 校验,缺失或非法时返回 422。</p>
475
537
  <h3>请求</h3>
476
538
  <pre><code class="language-http">GET /api/user/:id</code></pre>
477
539
  <h3>路径参数</h3>
@@ -480,13 +542,15 @@ throw new Error('Something went wrong');</code></pre>
480
542
  <tr>
481
543
  <th>参数</th>
482
544
  <th>类型</th>
545
+ <th>必填</th>
483
546
  <th>说明</th>
484
547
  </tr>
485
548
  </thead>
486
549
  <tbody>
487
550
  <tr>
488
551
  <td>id</td>
489
- <td>number</td>
552
+ <td>string</td>
553
+ <td>是</td>
490
554
  <td>用户ID</td>
491
555
  </tr>
492
556
  </tbody>
@@ -502,12 +566,19 @@ throw new Error('Something went wrong');</code></pre>
502
566
  }
503
567
  }</code></pre>
504
568
  <h3>错误响应</h3>
569
+ <p>404 用户不存在:</p>
505
570
  <pre><code class="language-json">{
506
571
  "success": false,
507
572
  "message": "User not found"
573
+ }</code></pre>
574
+ <p>422 参数校验失败(如 id 为空):</p>
575
+ <pre><code class="language-json">{
576
+ "success": false,
577
+ "message": "用户 id 不能为空",
578
+ "errors": [{ "field": "id", "message": "用户 id 不能为空" }]
508
579
  }</code></pre>
509
580
  <h2>创建用户</h2>
510
- <p>创建新用户。</p>
581
+ <p>创建新用户。请求体会经过 Joi 校验(<code>name</code> 必填、长度等),未通过返回 422。</p>
511
582
  <h3>请求</h3>
512
583
  <pre><code class="language-http">POST /api/user
513
584
  Content-Type: application/json</code></pre>
@@ -531,14 +602,20 @@ Content-Type: application/json</code></pre>
531
602
  <td>name</td>
532
603
  <td>string</td>
533
604
  <td>是</td>
534
- <td>用户姓名</td>
605
+ <td>用户姓名(1~100 字符)</td>
535
606
  </tr>
536
607
  <tr>
537
608
  <td>email</td>
538
609
  <td>string</td>
539
- <td>是</td>
610
+ <td>否</td>
540
611
  <td>用户邮箱</td>
541
612
  </tr>
613
+ <tr>
614
+ <td>age</td>
615
+ <td>number</td>
616
+ <td>否</td>
617
+ <td>年龄(0~150)</td>
618
+ </tr>
542
619
  </tbody>
543
620
  </table>
544
621
  <h3>响应</h3>
@@ -550,9 +627,15 @@ Content-Type: application/json</code></pre>
550
627
  "email": "zhangsan@example.com",
551
628
  "createdAt": "2024-01-01T00:00:00.000Z"
552
629
  }
630
+ }</code></pre>
631
+ <h3>校验失败(422)</h3>
632
+ <pre><code class="language-json">{
633
+ "success": false,
634
+ "message": "用户名为必填",
635
+ "errors": [{ "field": "name", "message": "用户名为必填" }]
553
636
  }</code></pre>
554
637
  <h2>更新用户</h2>
555
- <p>更新用户信息。</p>
638
+ <p>更新用户信息。路径参数与请求体均会校验,至少需提供一个要更新的字段。</p>
556
639
  <h3>请求</h3>
557
640
  <pre><code class="language-http">PUT /api/user/:id
558
641
  Content-Type: application/json</code></pre>
@@ -568,16 +651,18 @@ Content-Type: application/json</code></pre>
568
651
  <tbody>
569
652
  <tr>
570
653
  <td>id</td>
571
- <td>number</td>
572
- <td>用户ID</td>
654
+ <td>string</td>
655
+ <td>用户ID(必填)</td>
573
656
  </tr>
574
657
  </tbody>
575
658
  </table>
576
659
  <h3>请求体</h3>
577
660
  <pre><code class="language-json">{
578
661
  "name": "李四",
579
- "email": "lisi@example.com"
662
+ "email": "lisi@example.com",
663
+ "age": 25
580
664
  }</code></pre>
665
+ <p>可选字段:<code>name</code>(1~100 字符)、<code>email</code>、<code>age</code>(0~150),至少填一项。</p>
581
666
  <h3>响应</h3>
582
667
  <pre><code class="language-json">{
583
668
  "success": true,
@@ -590,7 +675,7 @@ Content-Type: application/json</code></pre>
590
675
  }
591
676
  }</code></pre>
592
677
  <h2>删除用户</h2>
593
- <p>删除指定用户。</p>
678
+ <p>删除指定用户。路径参数 <code>id</code> 会经过校验。</p>
594
679
  <h3>请求</h3>
595
680
  <pre><code class="language-http">DELETE /api/user/:id</code></pre>
596
681
  <h3>路径参数</h3>
@@ -605,14 +690,15 @@ Content-Type: application/json</code></pre>
605
690
  <tbody>
606
691
  <tr>
607
692
  <td>id</td>
608
- <td>number</td>
609
- <td>用户ID</td>
693
+ <td>string</td>
694
+ <td>用户ID(必填)</td>
610
695
  </tr>
611
696
  </tbody>
612
697
  </table>
613
698
  <h3>响应</h3>
614
699
  <pre><code class="language-http">204 No Content</code></pre>
615
700
  <h3>错误响应</h3>
701
+ <p>404 用户不存在 / 422 参数校验失败(格式同获取用户详情)。</p>
616
702
  <pre><code class="language-json">{
617
703
  "success": false,
618
704
  "message": "User not found"