[ Laravel從入門到精通 ] 編寫 JSON API —— 基於資源控制器和 API 資源類快速構建 API 介面
在上篇教程中學院君給大家簡單介紹 RESTful 風格 API 的設計原則和最佳實踐,接下來,我們將在 Laravel 專案中通過例項來演示如何編寫遵循 RESTful 風格的 JSON API 介面。
註冊遵循 REST 規範的 API 路由
其實我們之前在待辦任務專案中已經將這樣的 API 介面的骨架都搭建起來了,Laravel 框架對 RESTful 風格 API 支援非常友好,可以通過框架內建的資源控制器結合資源路由方法快速構建起遵循 REST 規範的 API 路由,這隻需要兩步操作即可辦到:
- 首先通過
php artisan make:controller TaskController --resource
建立資源控制器; - 然後在路由檔案
routes/api.php
中通過Route::resource('tasks', 'TaskController');
註冊對映上述資源控制器的 API 路由。
這樣,我們就構建起了遵循 REST 規範的 API 骨架:
然後,對於 API 介面而言,建立資源表單頁面和編輯資源表單頁面無需額外的路由,所以我們需要在資源控制器 app/Http/Controllers/TaskController.php
中將對應的 create
方法和 edit
方法刪除,同時在註冊資源路由的時候將這兩個路由排除:
Route::resource('tasks', 'TaskController', ['except' => ['create', 'edit']]);
這樣,最終的 API 路由資訊如下:
返回 JSON 響應
繼續後面的操作之前,假設你之前已經編寫好了待辦任務專案(如果沒有的話就從 Github 上將該專案克隆到本地並進行初始化,該專案的 Github 地址是: https://github.com/nonfu/todoapp ),為相應的業務邏輯準備好了模型和資料庫,並且編譯過前端資源,可以在前端頁面對任務資料進行增刪改查操作。
此外,Laravel 框架對 JSON 格式的 HTTP 響應支援也非常有好,如果響應返回的資料格式是陣列、集合或則模型例項,Laravel 預設都會將其轉化為 JSON 響應,而不需要你手動呼叫 json_encode
函式進行顯式轉化(對應的底層處理邏輯可以參考 Laravel 響應類 Response 剖析 這篇教程)。此外,如果想要對返回的資源資料格式進行更多的自定義,還可以藉助API 資源類對模型資料進行轉化再返回 JSON 響應。
構建簡單的 JSON 響應
接下來,我們不借助 API 資源類完成一些簡單的 JSON 響應業務程式碼編寫,關於新增、更新和刪除操作,之前在待辦任務專案中已經編寫過相應的程式碼了,我們只需要編寫獲取任務列表和任務詳情 API 介面資料的程式碼即可:
/** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { return Task::where('user_id', auth('api')->user()->id)->get(); } /** * Display the specified resource. * * @paramint$id * @return \Illuminate\Http\Response */ public function show($id) { return Task::findOrFail($id); }
然後我們註冊一個新使用者登入後跳轉到 http://todo.test/home
頁面新增幾個新任務:
然後通過 http://todo.test/api/tasks
即可獲取 JSON 格式的任務列表:
通過 http://todo.test/api/tasks/1
指定具體的任務 ID,也可以獲取到對應的 JSON 格式的單個任務資料:
可見,在 Laravel API 介面中,返回 JSON 格式響應資料是非常方便的,不管是資料庫查詢結果,還是 Eloquent 模型例項,還是集合資料,以及陣列和其它物件例項,都會被自動轉化為 JSON 格式資料。
基於 API 資源類構建自定義格式的 JSON 響應
資源類
如官方文件所言,一個 API 資源類表示一個單獨的需要被轉化為 JSON 資料結構的模型,而且使用 API 資源類的時候,往往是需要對某些模型欄位的轉化進行自定義的情況下,比如上面的示例中,我們可以對返回某個任務例項的 show
方法使用 API 資源類將模型例項轉化為 JSON 格式資料。
使用 API 資源類之前,需要先為對應模型類建立資源類:
php artisan make:resource Task
該命令會在 app/Http/Resources
目錄下生成 Task.php
資源類,然後我們可以將資源控制器的 show
方法改寫如下:
public function show($id) { return new \App\Http\Resources\Task(Task::find($id)); }
這種方式返回的資料和之前差不多,只是多了一個 data 層將資料包裹在裡面:
如果想要自定義返回的欄位和資料,可以自定義該資源類中的 toArray
方法,當我們將呼叫資源類轉化為 JSON 資料時,呼叫的正是該方法:
/** * Transform the resource into an array. * * @param\Illuminate\Http\Request$request * @return array */ public function toArray($request) { return [ 'id' => $this->id, 'text' => $this->text, 'completed' => $this->is_completed ? 'yes' : 'no' ]; }
我們可以在 $this
例項上呼叫模型類例項的任何欄位,原理是資源類底層會通過魔術方法 __get
將其轉化為呼叫例項化資源類時傳入的模型例項上的對應欄位。這樣一來,對應的 API 介面返回資料就變成這樣了:
如果想要在資源類中附帶關聯模型,也很簡單,在查詢的時候通過渴求式查詢帶上要關聯的模型:
public function show($id) { return new \App\Http\Resources\Task(Task::with(['user' => function($query) { $query->select('id', 'name'); }])->find($id)); }
然後在 Task
資源類的 toArray
方法中帶上這個關聯模型對應欄位即可:
資源集合
如果要同時返回多個模型例項,比如資源控制器中的 index
方法就是這種場景,顯然上面這個呼叫方式不適用,好在資源類中還提供了一個 collection
方法,通過該方法即可包裹模型例項集合以便應用資源類的 toArray
方法對返回資料格式進行自定義:
public function index() { $tasks = Task::where('user_id', auth('api')->user()->id)->with('user')->get(); return \App\Http\Resources\Task::collection($tasks); }
這個時候返回響應的資料格式如下:
每個模型例項中都包含一個 user
欄位,而對同一個使用者來說,不同的任務對應的使用者資訊都是一致的,因此,需要對這個返回資料格式進行優化,此時,藉助資源類提供的 collection
方法就不能滿足我們的需求了,我們需要建立額外的資源集合類來對返回的模型集合資料格式進行定義:
php artisan make:resource TaskCollection
編輯新生成的資源集合類 app/Http/Resources/TaskCollection.php
程式碼如下:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class TaskCollection extends ResourceCollection { public $collects = \App\Task::class; /** * Transform the resource collection into an array. * * @param\Illuminate\Http\Request$request * @return array */ public function toArray($request) { return [ 'tasks' => $this->collection->map(function ($task) { return $task->only(['id', 'text', 'is_completed']); }), 'user' => $this->collection->first()->user->only(['id', 'name']), ]; } }
預設情況下,如果資源類存在的話,資源集合類的 $collects
屬性值是對應的資源類,比如這裡預設是 App\Http\Resources\Task
,如果你不想複用這個資源類的轉化邏輯,可以將其設定為對應模型類進行覆蓋,比如我這裡就是這麼做的,此外,在 toArray
方法中,我還將任務資料和使用者資料分隔開返回。這樣,再次訪問 http://todo.test/api/tasks
,返回資料格式如下:
分頁資料
除此之外,返回分頁資料也是一種很常見的場景,Laravel 框架預設對資源集合的分頁資料格式化提供了友好的支援。還是以 index
方法為例,我們將該方法改寫如下已支援對任務進行分頁顯示(每頁顯示10個任務):
public function index() { $tasks = Task::where('user_id', auth('api')->user()->id)->with('user')->paginate(10); return new TaskCollection($tasks); }
然後,我們不需要對資源集合類 TaskCollection
做任何修改,Laravel 框架底層會自動為我們在響應資料中加上分頁資料:
是不是很方便?好了,關於資源類和資源集合類學院君就簡單介紹到這裡,更多使用方法,請參考官方文件。
以上就是在 Laravel 框架中基於資源控制器和 API 資源類快速構建 JSON API 介面的入門教程,相關程式碼已經推送到 Github 程式碼倉庫 ,希望看完這篇教程,你可以快速上手 Laravel API 介面編寫。