
1. Laravel API开发基础概念Laravel作为现代PHP框架的代表其API开发能力一直备受开发者青睐。在开始构建API之前我们需要明确几个核心概念RESTful API是一种遵循REST架构风格的网络API设计规范。它使用HTTP协议定义资源操作通过不同的HTTP方法GET/POST/PUT/DELETE等来表达对资源的操作意图。Laravel天然支持RESTful风格这让我们可以快速构建符合行业标准的API接口。JSON:API是RESTful API的一种具体实现规范它定义了客户端和服务器之间交互的详细规则。Laravel通过JsonApiResource类提供了对JSON:API规范的内置支持包括资源对象结构、关系处理、稀疏字段集等功能。在实际项目中我们通常会遇到以下几种API响应格式需求基础数据响应返回简单的数据结构和状态码资源集合返回分页或不分页的资源列表嵌套关系处理资源之间的关联关系错误处理统一的错误响应格式2. 环境准备与项目初始化2.1 安装Laravel首先确保系统已安装PHP 8.0和Composer然后通过以下命令创建新项目composer create-project laravel/laravel laravel-api-project cd laravel-api-project2.2 数据库配置修改.env文件配置数据库连接DB_CONNECTIONmysql DB_HOST127.0.0.1 DB_PORT3306 DB_DATABASElaravel_api DB_USERNAMEroot DB_PASSWORD2.3 安装常用扩展包对于API开发推荐安装以下扩展包composer require laravel/sanctum composer require spatie/laravel-query-builderSanctum提供轻量级的API认证系统而Query Builder则能帮助我们优雅地处理复杂的API查询参数。3. 构建第一个API资源3.1 创建模型和迁移让我们以一个博客系统为例创建Post模型php artisan make:model Post -m编辑迁移文件Schema::create(posts, function (Blueprint $table) { $table-id(); $table-string(title); $table-text(content); $table-foreignId(user_id)-constrained(); $table-timestamps(); });运行迁移php artisan migrate3.2 创建API资源Laravel提供了便捷的命令生成资源类php artisan make:resource PostResource生成的PostResource位于app/Http/Resources目录下我们可以这样定义?php namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class PostResource extends JsonResource { public function toArray(Request $request): array { return [ id $this-id, title $this-title, content $this-content, created_at $this-created_at-format(Y-m-d H:i:s), updated_at $this-updated_at-format(Y-m-d H:i:s), ]; } }3.3 创建控制器和路由生成控制器php artisan make:controller Api/PostController --api在routes/api.php中添加路由use App\Http\Controllers\Api\PostController; Route::apiResource(posts, PostController::class);控制器基础实现?php namespace App\Http\Controllers\Api; use App\Http\Resources\PostResource; use App\Models\Post; use App\Http\Controllers\Controller; class PostController extends Controller { public function index() { return PostResource::collection(Post::paginate()); } public function show(Post $post) { return new PostResource($post); } // 其他方法... }4. 高级API功能实现4.1 条件属性与关系在实际项目中我们经常需要根据不同的条件返回不同的字段。Laravel资源提供了灵活的条件属性处理public function toArray(Request $request): array { return [ id $this-id, title $this-title, content $this-when( $request-user() $request-user()-can(view-content, $this), $this-content ), secret_notes $this-when( $request-user() $request-user()-isAdmin(), $this-secret_notes ), comments_count $this-whenCounted(comments), author new UserResource($this-whenLoaded(author)), ]; }4.2 分页与元数据Laravel资源集合天然支持分页public function index() { $posts Post::query() -with([author, comments]) -paginate(request(per_page, 15)); return PostResource::collection($posts); }可以自定义分页元数据public function with($request) { return [ meta [ version 1.0.0, api_status stable ] ]; }4.3 验证与错误处理创建表单请求验证php artisan make:request StorePostRequest定义验证规则public function rules() { return [ title required|string|max:255, content required|string, tags sometimes|array, tags.* exists:tags,id ]; }统一错误响应格式public function failedValidation(Validator $validator) { throw new HttpResponseException(response()-json([ errors $validator-errors(), message The given data was invalid. ], 422)); }5. API安全与性能优化5.1 认证与授权使用Sanctum进行API认证php artisan vendor:publish --providerLaravel\Sanctum\SanctumServiceProvider php artisan migrate创建认证控制器public function login(Request $request) { $credentials $request-validate([ email required|email, password required ]); if (!Auth::attempt($credentials)) { return response()-json([message Unauthorized], 401); } $token $request-user()-createToken(api-token)-plainTextToken; return response()-json([token $token]); }保护路由Route::middleware(auth:sanctum)-group(function () { Route::apiResource(posts, PostController::class)-except([index, show]); });5.2 缓存策略实现简单的缓存策略public function index() { $cacheKey posts_ . request(page, 1) . _ . request(per_page, 15); return Cache::remember($cacheKey, now()-addMinutes(30), function () { $posts Post::query() -with([author, comments]) -paginate(request(per_page, 15)); return PostResource::collection($posts); }); }5.3 查询优化使用Eloquent的延迟加载和查询优化public function show(Post $post) { $post-load([ author function ($query) { $query-select([id, name, avatar]); }, comments function ($query) { $query-latest()-limit(10); } ]); return new PostResource($post); }6. 测试与文档6.1 API测试编写基础的API测试public function test_can_get_posts() { $posts Post::factory()-count(3)-create(); $response $this-getJson(/api/posts); $response-assertStatus(200) -assertJsonCount(3, data) -assertJsonStructure([ data [ * [id, title, content] ] ]); }6.2 API文档生成使用Scribe生成API文档composer require --dev knuckleswtf/scribe php artisan vendor:publish --providerKnuckles\Scribe\ScribeServiceProvider --tagscribe-config为路由添加注解/** * group 博客管理 * * 获取文章列表 * * queryParam page 页码 Example: 1 * queryParam per_page 每页数量 Example: 15 * * responseField data 文章列表 * responseField links 分页链接 * responseField meta 分页元数据 */ public function index() { // ... }生成文档php artisan scribe:generate7. 实际项目中的经验分享7.1 常见问题解决N1查询问题 总是使用with()预加载关联关系特别是在返回集合时。可以使用Laravel Debugbar来检测N1问题。数据转换问题 对于日期、金额等特殊格式统一在资源类中处理不要在多个地方重复转换。API版本控制 建议从一开始就考虑版本控制可以在路由中使用/api/v1/前缀或者在Accept头中指定版本。7.2 性能优化技巧选择性字段加载Post::query()-select([id, title, created_at])-paginate();使用简单分页Post::simplePaginate();关闭资源包装 在AppServiceProvider中添加JsonResource::withoutWrapping();7.3 项目结构建议对于大型API项目推荐以下结构app/ ├── Http/ │ ├── Controllers/ │ │ └── Api/ │ │ ├── V1/ │ │ │ ├── PostController.php │ │ │ └── UserController.php │ │ └── V2/ │ ├── Resources/ │ │ ├── V1/ │ │ │ ├── PostResource.php │ │ │ └── UserResource.php │ │ └── V2/ │ └── Requests/ │ ├── V1/ │ │ ├── StorePostRequest.php │ │ └── UpdatePostRequest.php │ └── V2/这种结构可以很好地支持API版本演进同时保持代码组织清晰。