初始化

This commit is contained in:
2026-03-05 21:27:11 +08:00
commit 130de0fd5d
140 changed files with 21972 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
# API 统一响应格式
## 成功响应
```json
{
"data": { ... },
"meta": {
"page": 1,
"pageSize": 20,
"total": 100,
"totalPages": 5
}
}
```
## 错误响应
```json
{
"error": "Human-readable error message",
"code": "VALIDATION_ERROR",
"details": [ ... ]
}
```
## HTTP 状态码
| 状态码 | 场景 |
|--------|------|
| 200 | 查询/更新成功 |
| 201 | 创建成功 |
| 204 | 删除成功(无响应体) |
| 400 | 请求参数验证失败 |
| 401 | 未认证 |
| 403 | 已认证但无权限 |
| 404 | 资源不存在 |
| 409 | 资源冲突(如重复创建) |
| 422 | 业务逻辑错误 |
| 429 | 请求频率超限 |
| 500 | 服务器内部错误 |

View File

@@ -0,0 +1,156 @@
# API Scaffold — 代码模板与异常体系
> 主流程见 SKILL.md本文档为 Controller/Service/FormRequest/路由 的完整代码模板。
## Hyperf 分层目录约定
| 文件 | 路径 |
|------|------|
| Controller | `app/Controller/Admin/<Resource>Controller.php` |
| Service | `app/Service/<Module>/<Resource>Service.php` |
| FormRequest | `app/Request/<Module>/Create<Resource>Request.php` |
| Model | `app/Model/<Module>/<Resource>.php`(如不存在) |
| Route | `app/Http/Admin/Router/<resource>.php` |
## Controller 模板
```php
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Request\{{Module}}\Create{{Resource}}Request;
use App\Service\{{Module}}\{{Resource}}Service;
use Hyperf\Di\Annotation\Inject;
#[Controller(prefix: '/admin/{{route-path}}')]
class {{Resource}}Controller extends AbstractController
{
#[Inject]
protected {{Resource}}Service $service;
#[RequestMapping(path: '', methods: ['GET'])]
public function list(RequestInterface $request): ResponseInterface {
$params = $request->all();
$result = $this->service->getPageList($params);
return $this->success($result);
}
#[RequestMapping(path: '{id:\d+}', methods: ['GET'])]
public function detail(int $id): ResponseInterface {
$result = $this->service->getById($id);
return $this->success($result);
}
#[RequestMapping(path: '', methods: ['POST'])]
public function create(Create{{Resource}}Request $request): ResponseInterface {
$data = $request->validated();
$result = $this->service->create($data);
return $this->success($result, 201);
}
#[RequestMapping(path: '{id:\d+}', methods: ['PUT'])]
public function update(int $id, Create{{Resource}}Request $request): ResponseInterface {
$data = $request->validated();
$result = $this->service->update($id, $data);
return $this->success($result);
}
#[RequestMapping(path: '{id:\d+}', methods: ['DELETE'])]
public function delete(int $id): ResponseInterface {
$this->service->delete($id);
return $this->success(null, message: 'Deleted');
}
}
```
## Service 模板
```php
<?php
namespace App\Service\{{Module}};
use App\Model\{{Module}}\{{Resource}};
use App\Exception\BusinessException;
use Hyperf\DbConnection\Db;
class {{Resource}}Service
{
public function getPageList(array $params): array {
$query = {{Resource}}::query();
if (!empty($params['status'])) $query->where('status', $params['status']);
$page = (int) ($params['page'] ?? 1);
$pageSize = (int) ($params['page_size'] ?? 10);
$total = $query->count();
$items = $query->orderByDesc('id')->offset(($page - 1) * $pageSize)->limit($pageSize)->get();
return ['items' => $items, 'total' => $total];
}
public function getById(int $id): {{Resource}} {
$record = {{Resource}}::find($id);
if (!$record) throw new BusinessException(404, '{{Resource}} not found');
return $record;
}
public function create(array $data): {{Resource}} {
return Db::transaction(fn () => {{Resource}}::create($data));
}
public function update(int $id, array $data): {{Resource}} {
$record = $this->getById($id);
return Db::transaction(function () use ($record, $data) {
$record->update($data);
return $record->refresh();
});
}
public function delete(int $id): void {
$record = $this->getById($id);
$record->delete();
}
}
```
## FormRequest 模板
```php
<?php
namespace App\Request\{{Module}};
use Hyperf\Validation\Request\FormRequest;
class Create{{Resource}}Request extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array {
return [ /* Define validation rules based on resource fields */ ];
}
}
```
## 路由注册
```php
// app/Http/Admin/Router/{{resource}}.php
use App\Controller\Admin\{{Resource}}Controller;
use Hyperf\HttpServer\Router\Router;
Router::addGroup('/admin/{{route-path}}', function () {
Router::get('', [{{Resource}}Controller::class, 'list']);
Router::get('/{id:\d+}', [{{Resource}}Controller::class, 'detail']);
Router::post('', [{{Resource}}Controller::class, 'create']);
Router::put('/{id:\d+}', [{{Resource}}Controller::class, 'update']);
Router::delete('/{id:\d+}', [{{Resource}}Controller::class, 'delete']);
}, ['middleware' => [AccessTokenMiddleware::class, PermissionMiddleware::class]]);
```
## 统一响应格式
```php
protected function success(mixed $data = null, int $code = 200, string $message = 'ok'): ResponseInterface {
return $this->response->json(['code' => $code, 'message' => $message, 'data' => $data]);
}
protected function error(string $message, int $code = 500, mixed $data = null): ResponseInterface {
return $this->response->json(['code' => $code, 'message' => $message, 'data' => $data]);
}
```

View File

@@ -0,0 +1,100 @@
# API Scaffold — 分级异常体系
> 主流程见 SKILL.md本文档为异常分级与 AppExceptionHandler 完整实现。
## 异常分级
| 异常类 | 场景 | HTTP 状态码 | 日志级别 | 是否通知运维 |
|---|---|---|---|---|
| `BusinessException` | 可预期的业务错误 | 400/403/404/409/422 | warning | ❌ |
| `ValidationException` | 参数校验失败 | 422 | info | ❌ |
| `SystemException` | 不可预期的系统故障 | 500/502/503 | error | ✅ |
## BusinessException / SystemException 定义
```php
// app/Exception/BusinessException.php
class BusinessException extends ServerException
{
public function __construct(int $code = 400, string $message = 'Business error', public readonly bool $isOperational = true)
{
parent::__construct($message, $code);
}
}
// app/Exception/SystemException.php
class SystemException extends ServerException
{
public function __construct(string $message = 'System error', int $code = 500, public readonly bool $isOperational = false, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
```
## AppExceptionHandler
```php
<?php
namespace App\Exception\Handler;
use App\Exception\BusinessException;
use App\Exception\SystemException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Validation\ValidationException;
class AppExceptionHandler extends ExceptionHandler
{
public function handle(\Throwable $throwable, ResponseInterface $response): ResponseInterface
{
$this->stopPropagation();
$body = match (true) {
$throwable instanceof ValidationException => ['code' => 422, 'message' => 'Validation failed', 'data' => $throwable->validator->errors()->toArray()],
$throwable instanceof BusinessException => ['code' => $throwable->getCode(), 'message' => $throwable->getMessage(), 'data' => null],
$throwable instanceof SystemException => $this->handleSystemException($throwable),
default => $this->handleUnexpected($throwable),
};
$statusCode = ($body['code'] >= 100 && $body['code'] < 600) ? $body['code'] : 500;
return $response->withStatus($statusCode)->withHeader('Content-Type', 'application/json')
->withBody(new SwooleStream(json_encode($body, JSON_UNESCAPED_UNICODE)));
}
private function handleSystemException(SystemException $e): array {
$this->logger->error('System exception', ['message' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
return ['code' => 500, 'message' => 'Internal server error', 'data' => null];
}
private function handleUnexpected(\Throwable $e): array {
$this->logger->critical('Unexpected exception', ['class' => get_class($e), 'message' => $e->getMessage()]);
return ['code' => 500, 'message' => 'Internal server error', 'data' => null];
}
public function isValid(\Throwable $throwable): bool { return true; }
}
```
## 异常选择决策
```
抛出异常?
├─ 用户输入/请求导致的?
│ ├─ 参数格式错误 → ValidationExceptionFormRequest 自动抛出)
│ ├─ 资源不存在 → BusinessException(404)
│ ├─ 无权限 → BusinessException(403)
│ └─ 业务规则冲突 → BusinessException(409/422)
└─ 系统/环境导致的?
├─ 数据库连接失败 → SystemException(503)
├─ 第三方 API 超时 → SystemException(502)
└─ 未知异常 → AppExceptionHandler 兜底
```
## Service 使用示例
```php
// Predictable: resource not found
throw new BusinessException(404, 'Order not found');
// Unpredictable: external system failure
throw new SystemException(message: 'ERP sync failed: connection timeout', previous: $e);
```