REST or REST-like APIs 的特点
- 围绕 “资源” 建立的, 用
url代表资源, 例如/cats代表所有的猫,/cats/15代表ID是15的猫。 - 与资源的交互只能用
http动词 - 无状态的,请求之间不会持久化会话身份验证,每个请求必须单独进行身份验证
- 它是可缓存和一致的, 无论请求者是谁,每个请求除了少数经过身份验证的特定请求外,都应返回同样的结果。
- 返回
json
生成 APIs
生成控制器
php artisan make:controller Api\DogsController --api
补充完整代码
// 使用 Eloquent 补充完整代码
class DogsController extends Controller
{
// 获取列表 GET /api/dogs
public function index(){
return Dog::all();
}
// 创建 POST /api/dogs with body: {'name':xxx, 'age':xx}
public function store(Request $request){
return Dog::create($request->only(['name', 'age']));
}
// 显示一个 GET /api/dogs/1
pulic function show($id){
return Dog::findOrFail($id);
}
// 更新数据 PATCH /api/dogs/3 with body: {name:'aaa', age:3}
public function updete(Request $request, $id){
$dog = Dog::findOrFail($id);
$dog->update($request->only(['name', 'age']));
return $dog;
}
// 删除数据 DELETE /api/dogs/2
public function destroy($id){
Dog::findOrFail($id)->delete();
}
}
接下来,绑定路由即可
Route::namespace('Api')->group(function(){
Route::apiResource('dogs', 'DogsController');
});
RESTful API 大功告成~ !
发送与接收 header
发送
Route::get('dogs', function () {
return respon(Dogs::all())
->header('X-Greatness-Index', 12);
})
接受
Route::get('dogs', function (Request $request) {
var_dump($request->header('Accept'));
});
分页
Route::get('dogs', function(){
return Dog::paginate(20);
// 等价于
return DB::table('dogs')->paginate(20);
});
我们将会得到
GET /dogs - Return results 1-20
GET /dogs?page=1 - Return results 1-20
GET /dogs?page=2 - Return results 21-40
输入示例
{
"current_page": 1,
"data": [
{
'name': 'Fido'
},
{
'name': 'Pickles'
},
{
'name': 'Spot'
}
]
"first_page_url": "http://myapp.com/api/dogs?page=1",
"from": 1,
"last_page": 2,
"last_page_url": "http://myapp.com/api/dogs?page=2",
"next_page_url": "http://myapp.com/api/dogs?page=2",
"path": "http://myapp.com/api/dogs",
"per_page": 2,
"prev_page_url": null,
"to": 2,
"total": 4
}
排序和过滤
对结果进行排序
// 简单排序 Handles /dogs?sort=name
Route::get('dogs', function(Request $request){
// 接收排序字段名,默认 'name'
$sortColumn = $request->input('sort', 'name');
return Dog::orderBy($sortColumn)->paginate(20);
});
// 控制排序方向 Handles /dogs?sort=name or /dogs?sort=-name
Route::get('dogs', function(){
$sortColumn = $request->input('sort', 'name');
$sortDirection = starts_with($sortColumn, '-') ? 'desc' : 'asc';
$sortColumn = ltrim($sortColumn, '-');
return Dog::orderBy($sortCoulmn, $sortDirection)->paginate(20);
});
// 多字段排序 Handles /dogs?sort=name,-weight
Route::get('dogs', function(Request $request){
$sorts = explod(',', $request->input('sort', ''));
$query = Dog::query();
foreach($sorts as $sortColumn){
$sortDiretion = starts_with($sortColumn, '-');
$sortCloumn = ltrim($sortColumn, '-');
$query->orderBy($sortColumn, $sortDiretion);
}
return $query->paginate(20);
});
过滤结果
// 单个过滤 ?filter=breed:Chihuahua
Route::get('dogs', function() {
$query = Dog::query();
$query->when(request()->filled('fillter'), function ($query) {
[$criteria, $value] = explode(':', request('filter'));
return $query->where($criteria, $value);
});
return $query->paginate(20);
});
// 多个过滤 ?filter=breed:chihuahua,color:brown
Route::get('dogs', function(Request $request){
$query = Dog::query();
$query->when(request()->filled('filter'), function($query){
$filters = expode(',', request('filter'));
foreach($filters as $filter){
[$criteria, $value] = explode(':', $filter);
$query->where($criteria, $value);
}
return $query;
});
return $query->paginate(20);
});
API 资源 (API Resources)
过去,Laravel中开发 API的首要挑战之一就是,如何转换数据。 简单的 API 可以将 Eloquent 对象作为 json 返回,但是大多数 API会超过这个需求。
在 Laravel 5.5 之后, 我们可以访问 Eloquent API resource 功能,它是一种定义了怎么把给定类的 Eloquent 对象(或者 对象集合 collection )转变成 API 结果的结构。
创建 资源类
执行命令
php artisan make:resource Dog
将创建一个新的类 app/Http/Resources/Dog.php ,并且有一个方法 toArray() ,如下:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Dog extends JsonResource
{
/**
* Transform the resource into an array
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
retutn parent::toArray($request);
}
}
这里,我们使用 toArray() 方法可以获取两个重要的参数,首先, 它可以访问 \Illuminate\Http\Request 对象,因此我们可以根据 请求参数、请求头或者其他重要的东西来自定义响应;其次, 它可以访问整个 Eloquent 对象, 只需通过访问 $this 上的属性和方法即可。
class Dog extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'breed' => $this->breed,
];
}
}
要使用新资源,更新任何返回单个 Dog的 API节点,你只需在响应上包裹此资源即可。如下:
use App\Dog;
use App\Http\Resources\Dog as DogResource;
Route::get('dogs/{dogId}', function($dogId){
return new DogResource(Dog::findOrFail($dogId));
})
资源集合 (Resource Collection)
use App\Dog;
use App\Http\Resource\Dog as DogResource;
Route::get('dogs', function() {
return DogResource::collection(Dog::all());
});
这个方法遍历传入的每个条目,然后用 DogResource API 资源转换它,然后返回集合。
对大多数 APIs 来说,已经足够了,但是如果你需要自定义结构或者增加元数据(metadata),你需要创建自定义资源 API 集合。
执行如下 shell 命令行
php artisan make:resource Dogcollection
将生成 App/Http/Resources/DogCollection.php 文件
<?php
namespace App\Http\Resource;
use Illuminate\Http\Resource\Json\ResourceCollection;
class DogCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
'links' => [
'self' => route('dogs.index'),
],
];
}
}
与 API resource 不同的是,我们处理的是资源集合,而不是单个资源,所以我们可以直接使用 $this->collection获取集合(已经转换过的)。
嵌套关系
API 相对复杂的一点就是 关系嵌套 。最简单的关系嵌套就是增加一个key , 这个 key 设置资源集合。
public function toArray(){
return [
'name' => $this->name,
'breed' => $this->breed,
'friends' => DogResource::collection($this->friends);
];
}
如果你想增加条件判断,只要在请求需要关系时,或者 Eloquent 已经懒加载时,才嵌套关系,则如下:
public function toArray(){
return [
'name' => $this->name,
'breed' => $this->breed,
// 如果已经懒加载时,加载关系
'bones' => BoneResource::collection($this->whenLoaded('bones')),
// 如果 请求中明确指出需要
'bones' => $this->when(
$request->get('include') == 'bones',
BoneResource::collection($this->bones)
),
];
}
资源 API 使用分页
就像你可以传递一个Eloquent模型集合到资源一样,你也可以传递一个分页器实例。
Route::get('dogs', function(){
return new DogCollection(Dog::paginate(2));
});
如果传递一个分页器实例,则转换后的结果将包含分页信息(第一页、最后一页、上一页和下一页)和有关整个集合的元信息。如下:
{
"data": [
{
"name": "Pickles", "breed": "Chorkie",
},
{
"breed": "Golden Retriever Mix",
}
],
"links": {
"first": "http://gooddogbrant.com/api/dogs?page=1",
"last": "http://gooddogbrant.com/api/dogs?page=3",
"prev": null,
"next": "http://gooddogbrant.com/api/dogs?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 3,
"path": "http://gooddogbrant.com/api/dogs", "per_page": 2,
"to": 2,
"total": 5
}
}
条件属性
您还可以指定仅在满足特定条件时,才在资源响应中的包含属性。
public function toArray($request) {
return [
'name' => $this->name,
'breed' => $this->breed,
'rating' => $this->when(Auth::user()->canSeeRatings(), 12),
];
}
更多自定义
详细了解如何更多自定义 API 请查看 文档
