Hyperf方案 RESTful API设计规范
?php/** * 案例051RESTful API设计规范 * 说明标准REST接口设计统一响应格式HTTP状态码规范使用 * 需要安装的包hyperf/http-server */declare(strict_types1);namespaceApp\Controller;useHyperf\HttpServer\Annotation\Controller;useHyperf\HttpServer\Annotation\DeleteMapping;useHyperf\HttpServer\Annotation\GetMapping;useHyperf\HttpServer\Annotation\PostMapping;useHyperf\HttpServer\Annotation\PutMapping;useHyperf\HttpServer\Contract\RequestInterface;useHyperf\HttpServer\Contract\ResponseInterface;/** * REST资源命名规则 * - 用名词复数/articles 不用 /getArticles * - 层级关系/users/{id}/orders 表示某用户的订单 * - 查询参数过滤/articles?statuspublishedpage1 * * HTTP方法语义 * GET - 查询幂等安全 * POST - 创建非幂等 * PUT - 全量更新幂等 * PATCH - 部分更新幂等 * DELETE - 删除幂等 */#[Controller(prefix:/api/v1/articles)]classArticleController{publicfunction__construct(privateRequestInterface$request,privateResponseInterface$response,privateArticleService$service,){}/** * 列表查询 GET /api/v1/articles * 支持分页、排序、过滤 */#[GetMapping(path:)]publicfunctionindex():\Psr\Http\Message\ResponseInterface{$page(int)$this-request-query(page,1);$sizemin((int)$this-request-query(size,20),100);// 最多100条$status$this-request-query(status);$keyword$this-request-query(keyword);$result$this-service-list($page,$size,$status,$keyword);// 200 OK 分页数据return$this-ok($result[items],[total$result[total],page$page,size$size,total_pagesceil($result[total]/$size),]);}/** * 查单条 GET /api/v1/articles/{id} */#[GetMapping(path:{id:\d})]publicfunctionshow(int$id):\Psr\Http\Message\ResponseInterface{$article$this-service-find($id);if(!$article){return$this-notFound(文章{$id}不存在);// 404}return$this-ok($article);}/** * 创建 POST /api/v1/articles */#[PostMapping(path:)]publicfunctionstore():\Psr\Http\Message\ResponseInterface{$data$this-request-post();// 校验简化版完整校验见案例058if(empty($data[title])){return$this-badRequest(标题不能为空);// 422}$article$this-service-create($data);// 201 CreatedLocation header指向新资源return$this-created($article,/api/v1/articles/{$article[id]});}/** * 全量更新 PUT /api/v1/articles/{id} */#[PutMapping(path:{id:\d})]publicfunctionupdate(int$id):\Psr\Http\Message\ResponseInterface{$article$this-service-find($id);if(!$article){return$this-notFound(文章{$id}不存在);}$data$this-request-post();$updated$this-service-update($id,$data);return$this-ok($updated);}/** * 删除 DELETE /api/v1/articles/{id} */#[DeleteMapping(path:{id:\d})]publicfunctiondestroy(int$id):\Psr\Http\Message\ResponseInterface{$article$this-service-find($id);if(!$article){return$this-notFound(文章{$id}不存在);}$this-service-delete($id);return$this-noContent();// 204 No Content成功但无响应体}// 响应辅助方法 /** 200 OK */privatefunctionok(mixed$data,array$meta[]):\Psr\Http\Message\ResponseInterface{$body[code0,messagesuccess,data$data];if(!empty($meta))$body[meta]$meta;return$this-response-json($body)-withStatus(200);}/** 201 Created */privatefunctioncreated(mixed$data,string$location):\Psr\Http\Message\ResponseInterface{$resp$this-response-json([code0,messagecreated,data$data])-withStatus(201);if($location)$resp$resp-withHeader(Location,$location);return$resp;}/** 204 No Content */privatefunctionnoContent():\Psr\Http\Message\ResponseInterface{return$this-response-raw()-withStatus(204);}/** 400 Bad Request */privatefunctionbadRequest(string$message):\Psr\Http\Message\ResponseInterface{return$this-response-json([code400,message$message])-withStatus(400);}/** 404 Not Found */privatefunctionnotFound(string$message):\Psr\Http\Message\ResponseInterface{return$this-response-json([code404,message$message])-withStatus(404);}}/** * ArticleService 简化版让文件能独立使用 */classArticleService{publicfunctionlist(int$page,int$size,?string$status,?string$keyword):array{$query\Hyperf\DbConnection\Db::table(articles);if($status)$query-where(status,$status);if($keyword)$query-where(title,like,%{$keyword}%);$total$query-count();$items$query-forPage($page,$size)-get()-toArray();returncompact(total,items);}publicfunctionfind(int$id):?array{$row\Hyperf\DbConnection\Db::table(articles)-find($id);return$row?(array)$row:null;}publicfunctioncreate(array$data):array{$id\Hyperf\DbConnection\Db::table(articles)-insertGetId(array_merge($data,[created_atdate(Y-m-d H:i:s)]));return$this-find($id);}publicfunctionupdate(int$id,array$data):array{\Hyperf\DbConnection\Db::table(articles)-where(id,$id)-update($data);return$this-find($id);}publicfunctiondelete(int$id):void{\Hyperf\DbConnection\Db::table(articles)-delete($id);}}