RESTful API #

一、API概述 #

1.1 RESTful设计原则 #

text
RESTful API设计原则
├── 使用HTTP动词
│   ├── GET - 获取资源
│   ├── POST - 创建资源
│   ├── PUT/PATCH - 更新资源
│   └── DELETE - 删除资源
├── 使用名词表示资源
│   ├── /users - 用户资源
│   ├── /posts - 文章资源
│   └── /comments - 评论资源
├── 使用HTTP状态码
│   ├── 200 - 成功
│   ├── 201 - 创建成功
│   ├── 400 - 请求错误
│   ├── 401 - 未认证
│   ├── 403 - 禁止访问
│   ├── 404 - 未找到
│   └── 500 - 服务器错误
└── 返回JSON格式

1.2 API路由 #

php
// routes/api.php
use App\Http\Controllers\Api\UserController;

Route::apiResource('users', UserController::class);

二、API控制器 #

2.1 创建API控制器 #

bash
php artisan make:controller Api/UserController --api

2.2 控制器实现 #

php
namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function index()
    {
        $users = User::paginate(10);
        return response()->json($users);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:8',
        ]);

        $user = User::create($validated);

        return response()->json([
            'message' => '用户创建成功',
            'data' => $user,
        ], 201);
    }

    public function show(User $user)
    {
        return response()->json($user);
    }

    public function update(Request $request, User $user)
    {
        $validated = $request->validate([
            'name' => 'sometimes|string|max:255',
            'email' => 'sometimes|email|unique:users,email,' . $user->id,
        ]);

        $user->update($validated);

        return response()->json([
            'message' => '用户更新成功',
            'data' => $user,
        ]);
    }

    public function destroy(User $user)
    {
        $user->delete();

        return response()->json(null, 204);
    }
}

三、API资源 #

3.1 创建资源类 #

bash
php artisan make:resource UserResource
php artisan make:resource UserCollection

3.2 资源类定义 #

php
// app/Http/Resources/UserResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at->toIso8601String(),
            'updated_at' => $this->updated_at->toIso8601String(),
        ];
    }
}

3.3 集合资源 #

php
// app/Http/Resources/UserCollection.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'meta' => [
                'total' => $this->total(),
                'count' => $this->count(),
                'per_page' => $this->perPage(),
                'current_page' => $this->currentPage(),
                'total_pages' => $this->lastPage(),
            ],
        ];
    }
}

3.4 使用资源 #

php
use App\Http\Resources\UserResource;
use App\Http\Resources\UserCollection;

// 单个资源
public function show(User $user)
{
    return new UserResource($user);
}

// 集合资源
public function index()
{
    $users = User::paginate(10);
    return new UserCollection($users);
}

// 或使用collection方法
public function index()
{
    return UserResource::collection(User::all());
}

3.5 条件属性 #

php
public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->when($request->user()->isAdmin(), $this->email),
        'secret' => $this->when($request->user()->isAdmin(), function () {
            return 'secret-value';
        }),
        $this->mergeWhen($request->user()->isAdmin(), [
            'first_name' => $this->first_name,
            'last_name' => $this->last_name,
        ]),
    ];
}

3.6 关联资源 #

php
public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'posts' => PostResource::collection($this->whenLoaded('posts')),
        'comments' => CommentResource::collection($this->whenLoaded('comments')),
    ];
}

四、分页 #

4.1 基本分页 #

php
public function index()
{
    $users = User::paginate(10);
    return UserResource::collection($users);
}

4.2 分页响应格式 #

json
{
    "data": [
        {"id": 1, "name": "John"},
        {"id": 2, "name": "Jane"}
    ],
    "links": {
        "first": "http://example.com/api/users?page=1",
        "last": "http://example.com/api/users?page=10",
        "prev": null,
        "next": "http://example.com/api/users?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 10,
        "path": "http://example.com/api/users",
        "per_page": 10,
        "to": 10,
        "total": 100
    }
}

4.3 简单分页 #

php
$users = User::simplePaginate(10);

4.4 游标分页 #

php
$users = User::cursorPaginate(10);

五、响应格式 #

5.1 标准响应 #

php
// 成功响应
return response()->json([
    'success' => true,
    'message' => '操作成功',
    'data' => $data,
]);

// 错误响应
return response()->json([
    'success' => false,
    'message' => '操作失败',
    'errors' => $errors,
], 400);

5.2 辅助方法 #

php
// 返回成功
return response()->success($data, '操作成功');

// 返回错误
return response()->error('操作失败', 400);

// 返回分页
return response()->paginate($paginator);

六、错误处理 #

6.1 异常处理 #

php
// app/Exceptions/Handler.php

public function render($request, Throwable $exception)
{
    if ($request->expectsJson()) {
        if ($exception instanceof ModelNotFoundException) {
            return response()->json([
                'message' => '资源未找到',
            ], 404);
        }

        if ($exception instanceof ValidationException) {
            return response()->json([
                'message' => '验证失败',
                'errors' => $exception->errors(),
            ], 422);
        }
    }

    return parent::render($request, $exception);
}

6.2 自定义异常 #

php
throw new \Exception('自定义错误', 400);

// 或使用abort
abort(404, '资源未找到');

七、API版本控制 #

7.1 URL版本控制 #

php
// routes/api.php
Route::prefix('v1')->group(function () {
    Route::apiResource('users', Api\V1\UserController::class);
});

Route::prefix('v2')->group(function () {
    Route::apiResource('users', Api\V2\UserController::class);
});

7.2 控制器组织 #

text
app/Http/Controllers/Api/
├── V1/
│   └── UserController.php
└── V2/
    └── UserController.php

八、API文档 #

8.1 使用Swagger #

bash
composer require darkaonline/l5-swagger
php artisan vendor:publish --provider="L5Swagger\L5SwaggerServiceProvider"

8.2 注释示例 #

php
/**
 * @OA\Get(
 *     path="/api/users",
 *     summary="获取用户列表",
 *     @OA\Response(response="200", description="成功")
 * )
 */
public function index()
{
    // ...
}

九、总结 #

9.1 核心要点 #

要点 说明
apiResource API资源路由
JsonResource JSON资源类
paginate 分页
response()->json() JSON响应

9.2 下一步 #

掌握了RESTful API后,让我们继续学习 API认证,了解API安全认证!

最后更新:2026-03-28