内容简介:为 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生成器和生成器函数
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Is Parallel Programming Hard, And, If So, What Can You Do About
Paul E. McKenney
The purpose of this book is to help you understand how to program shared-memory parallel machines without risking your sanity.1 By describing the algorithms and designs that have worked well in the pa......一起来看看 《Is Parallel Programming Hard, And, If So, What Can You Do About 》 这本书的介绍吧!