内容简介:为 API 编写文档和编写 API 接口功能同样重要,因为 API 大多是给别人用的,有了具备可读性的文档别人才知道怎么调用,以及如何处理返回结果。为了让文档编写过程更简单,Dingo 扩展包允许你在控制器中添加注解,然后通过 Artisan 命令根据这些注释生成 API 文档。下面我们就来演示下如何在 Dingo 路由控制器中添加注解并通过这些注解生成相应的 API 文档。注:通过闭包函数定义的 API 无法通过这种方式生成 API 文档。另外,注解看起来是以注释的方式呈现,但它是用于描述源代码的元数据,
为 API 编写文档和编写 API 接口功能同样重要,因为 API 大多是给别人用的,有了具备可读性的文档别人才知道怎么调用,以及如何处理返回结果。为了让文档编写过程更简单,Dingo 扩展包允许你在控制器中添加注解,然后通过 Artisan 命令根据这些注释生成 API 文档。
下面我们就来演示下如何在 Dingo 路由控制器中添加注解并通过这些注解生成相应的 API 文档。
注:通过闭包函数定义的 API 无法通过这种方式生成 API 文档。另外,注解看起来是以注释的方式呈现,但它是用于描述源代码的元数据,可以参与代码的编译和执行,而注释通常只是代码功能、参数和返回的描述而已,不参与代码的编译和执行。
Resource
Dingo API 中控制器通常以资源控制器的形式来表示,我们可以通过 @Resource
注解定义一个资源,打开 Api\TaskController.php
,在控制器类声明的前面添加注解如下:
/** * Task Resource Controller * @package App\Http\Controllers\Api * @Resource("Tasks") */ class TaskController extends ApiController { ... }
该注解的第一个参数用于描述资源的名称,还可以传递第二个参数定义资源路由的 base URI:
@Resource("Tasks", uri="/tasks")
Action
所谓 Action 指的是 HTTP 请求方法,目前 Dingo 支持 GET、POST、PUT、PATCH、DELETE 这五种请求方法,我们可以这样定义 TaskController
资源控制器 index
方法的 Action 注解:
/** * Display a listing of the resource. * @param Request $request * @return \Illuminate\Http\Response * @GET("/{?page,limit}" */ public function index(Request $request) { ... }
由于 index
方法支持分页,所以我们传递了额外的 page
、 limit
可选参数到 URI 中。如果是 store 方法的话,对应的 Action 注解如下:
/** * Store a newly created resource in storage. * * @param CreateTaskRequest $request * @return \Illuminate\Http\Response * @POST("/") */ public function store(CreateTaskRequest $request) { ... }
依次类推,后面的其它方法就不一一演示了,学院君会在最后给出最终的所有方法注解代码。
Version
Dingo API 有版本号的概念,我们可以在方法声明中通过 @Versions
注解添加该方法支持的版本:
/** * Display a listing of the resource. * @param Request $request * @return \Illuminate\Http\Response * @GET("/{?page,limit}" * @Versions({"v3"}) */ public function index(Request $request) { ... }
你可以传递多个版本号到集合参数中,如果不设置该注解,则表示支持所有版本的 Dingo API 接口。
Parameter
我们可以通过 @Parameters
和 @Parameter
注解来定义请求 URL 中的查询字符串参数, @Parameters
是一个集合,可以包含多组不同的参数组合,具体每一个参数则通过 @Parameter
来定义,比如我们可以通过这两个注解定义上面的 index
方法 URL 参数如下:
/** * Display a listing of the resource. * @param Request $request * @return \Illuminate\Http\Response * @GET("/{?page,limit}") * @Versions({"v3"}) * @Parameters({ * @Parameter("page", description="page number", type="integer", required=false, default=1), * @Parameter("limit", description="task item number per page", type="integer", required=false, default=10) * }) */ public function index(Request $request) { ... }
每个 @Parameter
注解可以通过额外的属性指定参数说明,通过参数名语义就可以看出相应的含义,这里就不展开介绍了。
Request
上面介绍的参数声明是针对 URL 查询字符串的,如果是通过 HTTP 请求实体传递的参数怎么声明呢?这些请求实体通常是 POST、PUT、PATCH 这些请求方法传递参数的方式,以 POST 为例,如果是通过表单传递的参数,可以这么定义注解:
/** * Store a newly created resource in storage. * * @param CreateTaskRequest $request * @return \Illuminate\Http\Response * @POST("/") * @Versions({"v3"}) * @Request("text=test&is_completed=1", contentType="application/x-www-form-urlencoded") */ public function store(CreateTaskRequest $request) { ... }
当然,这种定义方式将字段值写死了,对使用者来说不够明确,我们可以像下面这样为每个字段属性进行定义:
@Request("text={text}&is_completed={is_completed}", contentType="application/x-www-form-urlencoded", attributes={ @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), @Attribute("is_completed", type="boolean", required=true, description="task is completed or not", sample=1) })
如果是通过 JSON 格式传递请求参数的话,可以这么定义注解:
@Request({"text":"test task", "is_completed":1}, attributes={ @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), @Attribute("is_completed", type="boolean", required=true, description="task is completed or not", sample=1) })
由于 contentType
属性值默认就是 application/json
,所以不需要额外设置了,在 @Request
注解中,还可以通过 headers
属性设置额外的请求头,比如需要认证后才能访问 store
方法对应路由,这个时候需要在请求头中通过 Authorization 字段传递 Bearer Token 值,可以这样定义 @Request
注解实现:
@Request({"text":"test task", "is_completed":0}, headers={ "Authorization": "Bearer {API Access Token}" }, attributes={ @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), @Attribute("is_completed", type="boolean", required=false, description="task is completed or not", sample=0) })
Response
有了请求注解,自然也有与之对应的响应注解,我们可以通过 Dingo 扩展包提供的 @Response
注解声明响应状态码、内容类型、响应实体和响应头等信息:
/** * Store a newly created resource in storage. * * @param CreateTaskRequest $request * @return \Illuminate\Http\Response * @POST("/") * @Versions({"v3"}) * @Request({"text":"test task", "is_completed":0}, headers={ * "Authorization": "Bearer {API Access Token}" * }, attributes={ * @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), * @Attribute("is_completed", type="boolean", required=true, description="task is completed or not", sample=0) * }) * @Response(200, body={"data":{"id":4,"text":"Test Task 4","completed":"no","link":"http://todo.test/dingoapi/task/4"}}) */ public function store(CreateTaskRequest $request) { $request->validate([ 'text' => 'required|string' ]); $task = Task::create([ 'text' => $request->post('text'), 'user_id' => auth('api')->user()->id, 'is_completed' => Task::NOT_COMPLETED ]); return $this->response->item($task, new TaskTransformer()); }
和 @Request
注解一样,内容类型默认是 application/json
,无需额外指定,我们还可以通过 headers
属性设置额外的响应头,通过 attributes
属性描述每个响应字段的含义:
@Response(200, body={"data":{"id":1,"text":"Test Task 1","completed":"no","link":"http://todo.test/dingoapi/task/1"}}, attributes={ @Attribute("id", type="integer", description="the id of task", sample=1), @Attribute("text", type="string", description="the body of task", sample="test task"), @Attribute("completed", type="string", description="task is completed or not", sample="no"), @Attribute("link", type="string", description="task link", sample="http://todo.test/dingoapi/task/1") })
Transaction
最后,如果某个方法会返回多个不同的响应(比如处理异常状况),或者可以支持多组不同的请求/响应,可以通过一个事务注解( @Transaction
)将多组请求和响应囊括进来,每个组合里面支持一个请求和至少一个响应注解,比如我们可以通过这种方式定义 update
方法如下:
/** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response * @POST("/{id}") * @Versions({"v3"}) * @Parameters({ * @Parameter("id", type="integer", description="the ID of the task", required=true) * }) * @Transaction({ * @Request({"text":"test task", "is_completed":1}, headers={ * "Authorization": "Bearer {API Access Token}" * }, attributes={ * @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), * @Attribute("is_completed", type="boolean", required=true, description="task is completed or not", sample=1) * }), * @Response(200, body={"data":{"id":1,"text":"Test Task 1","completed":"no","link":"http://todo.test/dingoapi/task/1"}}, attributes={ * @Attribute("id", type="integer", description="the id of task", sample=1), * @Attribute("text", type="string", description="the body of task", sample="test task"), * @Attribute("completed", type="string", description="task is completed or not", sample="no"), * @Attribute("link", type="string", description="task link", sample="http://todo.test/dingoapi/task/1") * }), * @Response(404, body={"message":"404 not found", "status_code": 404}) * }) */ public function update(Request $request, $id) { $task = Task::findOrFail($id); $updatedTask = tap($task)->update(request()->only(['is_completed', 'text']))->fresh(); return $this->response->item($updatedTask, new TaskTransformer()); }
由于 update
方法可能会返回 200 和 404 两种响应,所以我们通过 @Transaction
将请求和响应注解都包含到一个集合项中。
生成 API 文档
至此,我们已经完成了 Dingo API 请求和响应从起始行到报文首部,再到报文实体所有 HTTP 报文组成部分的注解描述,接下来我们按照上面介绍的注解命令完成 Api\TaskController
控制器所有方法的注解定义:
/** * Task Resource Controller * @package App\Http\Controllers\Api * @Resource("Tasks", uri="/tasks") */ class TaskController extends ApiController { public function __construct() { $this->middleware('auth:api'); } /** * Display a listing of the resource. * @param Request $request * @return \Illuminate\Http\Response * @GET("/{?page,limit}") * @Versions({"v3"}) * @Parameters({ * @Parameter("page", description="page number", type="integer", required=false, default=1), * @Parameter("limit", description="task item number per page", type="integer", required=false, default=10) * }) * @Request(headers={ * "Authorization": "Bearer {API Access Token}" * }) * @Response(200, body={"data":{{"id":1,"text":"Test Task 1","completed":"no","link":"http://todo.test/dingoapi/task/1"}},"meta":{"pagination":{"total":4,"count":1,"per_page":1,"current_page":1,"total_pages":4,"links":{"next":"http://todo.test/dingoapi/tasks?page=2"}}}}) */ public function index(Request $request) { $limit = $request->input('limit') ? : 10; // 获取认证用户实例 $user = $request->user('api'); $tasks = Task::where('user_id', $user->id)->paginate($limit); return $this->response->paginator($tasks, new TaskTransformer()); } /** * Store a newly created resource in storage. * * @param CreateTaskRequest $request * @return \Illuminate\Http\Response * @POST("/") * @Versions({"v3"}) * @Request({"text":"test task", "is_completed":0}, headers={ * "Authorization": "Bearer {API Access Token}" * }, attributes={ * @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), * @Attribute("is_completed", type="boolean", required=true, description="task is completed or not", sample=0) * }) * @Response(200, body={"data":{"id":1,"text":"Test Task 1","completed":"no","link":"http://todo.test/dingoapi/task/1"}}, attributes={ * @Attribute("id", type="integer", description="the id of task", sample=1), * @Attribute("text", type="string", description="the body of task", sample="test task"), * @Attribute("completed", type="string", description="task is completed or not", sample="no"), * @Attribute("link", type="string", description="task link", sample="http://todo.test/dingoapi/task/1") * }) */ public function store(CreateTaskRequest $request) { $request->validate([ 'text' => 'required|string' ]); $task = Task::create([ 'text' => $request->post('text'), 'user_id' => auth('api')->user()->id, 'is_completed' => Task::NOT_COMPLETED ]); return $this->response->item($task, new TaskTransformer()); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response * @GET("/{id}") * @Parameters({ * @Parameter("id", type="integer", description="the ID of the task", required=true) * }) * @Versions({"v3"}) * @Transaction({ * @Request(headers={ * "Authorization": "Bearer {API Access Token}" * }), * @Response(200, body={"data":{"id":1,"text":"Test Task 1","completed":"no","link":"http://todo.test/dingoapi/task/1"}}, attributes={ * @Attribute("id", type="integer", description="the id of task", sample=1), * @Attribute("text", type="string", description="the body of task", sample="test task"), * @Attribute("completed", type="string", description="task is completed or not", sample="no"), * @Attribute("link", type="string", description="task link", sample="http://todo.test/dingoapi/task/1") * }), * @Response(404, body={"message":"404 not found", "status_code": 404}) * }) */ public function show($id) { $task = Task::findOrFail($id); return $this->response->item($task, new TaskTransformer()); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response * @PUT("/{id}") * @Parameters({ * @Parameter("id", type="integer", description="the ID of the task", required=true) * }) * @Versions({"v3"}) * @Transaction({ * @Request({"text":"test task", "is_completed":1}, headers={ * "Authorization": "Bearer {API Access Token}" * }, attributes={ * @Attribute("text", type="string", required=true, description="the body of task", sample="test task"), * @Attribute("is_completed", type="boolean", required=true, description="task is completed or not", sample=1) * }), * @Response(200, body={"data":{"id":1,"text":"Test Task 1","completed":"no","link":"http://todo.test/dingoapi/task/1"}}, attributes={ * @Attribute("id", type="integer", description="the id of task", sample=1), * @Attribute("text", type="string", description="the body of task", sample="test task"), * @Attribute("completed", type="string", description="task is completed or not", sample="no"), * @Attribute("link", type="string", description="task link", sample="http://todo.test/dingoapi/task/1") * }), * @Response(404, body={"message":"404 not found", "status_code": 404}) * }) */ public function update(Request $request, $id) { $task = Task::findOrFail($id); $updatedTask = tap($task)->update(request()->only(['is_completed', 'text']))->fresh(); return $this->response->item($updatedTask, new TaskTransformer()); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response * @DELETE("/{id}") * @Parameters({ * @Parameter("id", type="integer", description="the ID of the task", required=true) * }) * @Versions({"v3"}) * @Transaction({ * @Request(headers={ * "Authorization": "Bearer {API Access Token}" * }), * @Response(200, body={"message": "Task deleted"}), * @Response(404, body={"message":"404 not found", "status_code": 404}) * }) */ public function destroy($id) { $task = Task::findOrFail($id); $task->delete(); return response()->json(['message' => 'Task deleted'], 200); } }
最后通过 Dingo 扩展包提供的 API 文档生成命令来生成对应的文档了,在项目根目下执行如下 Artisan 命令:
php artisan api:docs --name TodoApp --output-file apidocs.md
我们通过 --name
指定文档名称,通过 --output-file
指定文档输出路径,生成的 API 文档将保存到项目根目录下,生成的文档效果图如下:
以上所述就是小编给大家介绍的《使用 Dingo API 扩展包快速构建 Laravel RESTful API(十二) —— 生成 API 文档》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用以 Tensorflow 为后端的 Keras 构建生成对抗网络的代码示例
- 巧用设计模式构建可配置Vue前端应用-活动页生成系统实践
- 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
- 实战生成对抗网络(二):生成手写数字
- 实战生成对抗网络[2]:生成手写数字
- 020.Python生成器和生成器函数
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ruby on Rails社区网站开发
布拉德伯纳 / 柳靖 / 2008-10 / 55.00元
《Ruby on Rails社区网站开发》全面探讨创建完整社区网站的开发过程。首先介绍开发一个内容简单的管理系统,之后逐渐添加新特性,以创建更完整的、使用Ruby on Rails 的Web 2.0 社区网站。还给出了开发和测试中的一些建议和提示,同时指导如何使网站更生动以及维护得更好。《Ruby on Rails社区网站开发》也探讨了如何与Flickr 、Google Maps 等其他平台集成,......一起来看看 《Ruby on Rails社区网站开发》 这本书的介绍吧!