0. 學前準備:
- 開發環境:Laravel Sail
- IDE:VS Code
- 視訊地址:【李炎恢】【Laravel / API介面 】【十天技能課堂系列】
1. 前言
這是一節短小精悍的 Laravel API 開發入門課,很基礎,但對我來說也很有用。
這個課程在時間順序上是在《李炎恢 / Laravel / 核心篇 / PHP框架 / 階段一》課程之後的,所以如果你跟我一樣只看這門課程的話,可能會遇到沒有資料庫資料的問題,但是這個問題容易解決,用 Laravel 自帶的資料填充功能填充一下就搞定。
另外,與視訊教程相比,我增加了兩點內容:
- 教程裡面沒有編寫
update
方法,我按照自己的理解補充了這部分內容,如果大家有更好的寫法,不妨在評論區 show you code - 我按照視訊裡面的編碼,發現儲存到資料庫裡面的使用者密碼是明文儲存,沒有加密,所以我改動了這部分內容
建議大家看一看原視訊哦。
還有,想知道如何使用 Laravel Sail 環境請參考:歷時三天,成功搭建Laravel Sail環境
2. 建立專案
curl -s https://laravel.build/yanhui | bash
如上所示,我建立一個名為 yanhui
的 Laravel 專案。
在 Terminal 中啟動專案:
./vendor/bin/sail up
如圖所示:
此時,我用瀏覽器開啟 http://localhost/
,就可以看到以下畫面,說明專案已經成功建立並且啟動(這個畫面我們不需要更改):
3. 建立用於 API 操作的資源控制器和對應路由
先在 Terminal 終端配置一下 Sail
命令,讓它變得簡短一點:
alias sail='bash vendor/bin/sail'
然後,使用以下命令建立 API 控制器
sail artisan make:controller UserController --api
--api
引數的意義是,從控制器中排除 create
和 edit
方法。
此處出現在我終端裡面的 爆紅 提示,是因為我在之前學習的時候已經建立過同名控制器,所以我再次演示就會這個提示,大家無視就好。
最後,我輸入 code .
,使用 VS code 開啟專案資料夾。
整個流程如下圖所示:
至此,控制器已經建立好,接下來是對應路由,在建立路由之前,我們我們可以使用 sail artisan route:list
命令來檢視一下,當前專案的路由列表是怎樣的(如果你是新建的專案,應該會看到如下所示的畫面):
接下來,我們開啟 routes\api.php
檔案,用一下程式碼,建立資源路由(檔案原本的程式碼我們先不改動,注意頂部引入控制器):
<?php
use App\Http\Controllers\UserController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::apiResource('user',UserController::class);
可以看到,與原檔案相比,我只新增了兩句程式碼:
use App\Http\Controllers\UserController;
Route::apiResource('user',UserController::class);
此時,我們再次在終端中輸入 sail artisan route:list
命令,可以看到如下畫面:
然後,我們來測試一下:
在 app\Http\Controllers\UserControllers.php
中,我們修改 index
方法:
public function index()
{
return '你好,Laravel~';
}
然後我們用瀏覽器開啟 http://localhost/api/user
可以看到如下畫面:
最後,我們用專業的介面除錯軟體 Postman
開啟http://localhost/api/user
可以看到以下畫面:
至此,控制器和路由建立並測試成功。
4. 建立一個專門用於生成 API 的控制類,然後繼承並呼叫它
在終端中使用命令建立控制器:
sail artisan make:controller ApiController
在生成的控制器中,我們編寫一個 create
方法:(檔案路徑:app\Http\Controllers\ApiController.php)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ApiController extends Controller
{
protected function create($msg = '', $code = 200, $data = [])
{
$result = [
// 返回狀態碼
'code'=>$code,
// 返回提示資訊
'msg'=>$msg,
// 返回資料
'data'=>$data,
];
return response($result);
}
}
然後,我們修改 UserController.php
檔案(檔案路徑:app\Http\Controllers\UserController.php)
使其繼承 ApiController
而不是原本的 Controller
,這樣我們就可以很自然地呼叫 create
方法,來生成標準的 API 返回資訊。
詳情如下:
class UserController extends ApiController
{
public function index()
{
return $this->create('請求成功',200,'你好,Laravel~');
}
此時,我們用Postman
再次傳送請求,可以看到如下畫面,說明控制類建立成功。
5. 資料列表和分頁
填充使用者資料
在本小節,我們將真正編寫第一個控制器方法的具體邏輯,但是,對於沒有看前置課程的同學來說,我們也將面臨一個問題:我們的資料庫裡面,沒有任何資料。
好在,這個問題我們可以用 Laravel 的資料填充功能來解決,至於填充的原理,我就不再贅述,只講怎麼做,想進一步瞭解原理的同學可以閱讀 Laravel 文件,或者參考本社群 《L01 Laravel 教程》的第 8 章第 4 小節。
資料填充第一步:建立 seeder 類
sail artisan make:seeder UserSeeder
生成的 UserSeeder 檔案位於:database\seeders\UserSeeder.php
讓我們編輯其中的 run
方法,如下所示:
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
User::factory(50)->create();
}
}
User::factory(50)->create();
這句程式碼會呼叫使用者工廠方法,為我們生成 50 條使用者資料。
使用者工廠,Laravel 預設自帶,檔案位於 database\factories\UserFactory.php,保持預設即可,暫時不需要做修改。
然後我們修改 DatabaseSeeder.php 檔案中的 run
方法,讓其呼叫我們建立的 UserSeeder 類:
檔案位置:database\seeders\DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
Model::unguard();
$this->call(UserSeeder::class);
Model::reguard();
}
}
現在,讓我們回到終端中,使用以下命令,生成 Laravel 預設的使用者資料表:
sail artisan migrate
接著用以下命令,填充資料
sail artisan db:seed
終端畫面如下所示:
至此,資料填充完成,如果你用 Navicat 等工具連線並開啟資料庫中的 users 表,就可以看到 Laravel 為我們生成的 50 條使用者資料,這裡就不演示了。
編寫 UserController 控制器的 index 方法
資料庫有了資料,我們接下來編寫的控制器方法才有意義,首先我們來看第一個控制器方法:
檔案位置:app\Http\Controllers\UserController.php
public function index()
{
// 資料獲取
// 返回資料
$data = User::select('id', 'name', 'email')->simplePaginate(10); // 簡單分頁
return $this->create('資料獲取成功', 200, $data);
}
可以看到,我通過查詢構造器,從 users 表的每條記錄中選出了三個欄位,並把所有的記錄進行簡單分頁,每頁展示 10 條資料。
用 Postman 進行除錯,可以看到如下畫面:
可以看到,之前填充的資料,被我們從資料庫調出來。
index 方法還有一些其他的寫法,這裡僅做記錄,有興趣的同學可以自己除錯以下寫法:
// 獲取全部可顯示欄位
$data = User::get();
// 獲取指定欄位
$data = User::select('id','name','email')->get();
// 獲取指定欄位並分頁
$data = User::select('id','name','email')->paginate(10);
至此,查詢所有資料並且分頁的方法,編寫完成。
6. 配置一個 404 的 HTTP 異常,並且用 JSON 格式返回(覆蓋系統自帶的 404 提示)
Larave 框架自帶 404 提示,為什麼我們還有重新寫一個呢?
因為自帶的 404 提示不符合 API 格式,這你讓前端很難做事的,所以,我們要重寫一個符合 API 格式的 404 提示,覆蓋原有的提示。
操作起來也簡單,兩步走:
- 在 resources/views 目錄下建立 errors 資料夾
- 在 resources/views/errors 目錄下建立 404.blade.php 檔案,並編寫返回的內容
你可以手動建立相關目錄和檔案,也可以像我一樣,在終端中使用命令來建立:
mkdir resources/views/errors && touch resources/views/errors/404.blade.php
同樣,因為我在之前已經建立過,所以,此時演示的時候,提示資料夾已存在。
接下來我們開始編寫 resources/views/errors 目錄下的 404.blade.php 檔案,很簡單,以下就是檔案的全部內容:
<?php
$result = [
// 返回狀態碼
'code' => 404,
// 返回提示資訊
'msg' => '資源不存在',
// 返回資料
'data' => [],
];
echo json_encode($result);
接下來我們在 Postman 裡面除錯一下,填入一個不存在的路徑,看看是不是我們自己編寫的 404 提示(如果各位的資訊顯示有點亂的話,可以注意我標記紅框的位置):
7. 展示單個資料 API
展示單個資料,對應的是控制器的 show 方法,通過傳入的 $id 來返回對應的使用者資訊。
但是根據 web 開發工程師第一準則:永遠不要相信使用者輸入的資料。
所以我們要考慮更多的東西,比如:
- 我們要求使用者傳入的引數是數字,但是使用者扔給我們一個單詞,我們該怎麼辦?
- 現在我們資料庫裡面數值的範圍在 1 - 50 之內,使用者給我們拋個 100 過來,超出了我們的資料範圍,我們又該返回什麼樣的資訊呢?
所以,show 方法編寫如下,具體的思路請看註釋部分文字:
檔案位置: app\Http\Controllers\UserControllers.php
public function show($id)
{
// 獲取資料
// 資料存在 返回成功資訊
// 資料不存在
// 引數超出範圍導致資料不存在
// 引數型別錯誤導致資料不存在
$data = User::select('id', 'name', 'email')->find($id);
if (isset($data)) {
return $this->create('資料獲取成功', 200, $data);
} else {
if (is_numeric($id)) {
return $this->create('使用者不存在', 204, []);
} else {
return $this->create('id 引數錯誤', 400, []);
}
}
}
Postman 除錯如下(正確引數):
非數字引數:
超範圍引數:
8. 新增資料 API
新增資料對應的控制器方法,是 store 方法,這部分程式碼我寫的與原視訊裡面有些不同,主要區別就是在講資料存入資料庫的時候,我將密碼用 md5()
函式進行加密,雖然這種方式也比較樸素,但是,起碼資料庫裡面的資料不再是赤裸裸的 123456
了,這是什麼?這就是進步啊~
檔案位置: app\Http\Controllers\UserControllers.php
編碼如下:
public function store(Request $request)
{
// 接收資料
$data = $request->all();
// 資料驗證
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'email' => 'required|min:2|max:50|email',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
} else {
$newUser = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => md5($request->password),
]);
$newUser = User::select('id', 'name', 'email')->find($newUser['id']);
return $this->create('使用者建立成功', 200, $newUser);
}
}
關於資料驗證程式碼的解析請看原視訊,或者參考本社群 《L01 Laravel 教程》的第 8 章第 4 小節。或者參考本社群 《L01 Laravel 教程》的第 6 章,此處點到為止。
以下是 Postman 除錯環節,請注意我標紅框的部分,都是細節哦:
9. 刪除資料 API
有增加就有刪除,就連後端人員的自嘲——增刪改查工程師 的頭兩個字,也是 增 和 刪 。
刪除資料對應的控制器方法,是 destroy 方法,其邏輯與增加資料很相似。
檔案位置: app\Http\Controllers\UserControllers.php
編碼如下:
public function destroy($id)
{
// 獲取資料
// 資料存在,刪除
// 資料不存在
// 引數超出範圍導致資料不存在
// 引數型別錯誤導致資料不存在
$data = User::find($id);
if (isset($data)) {
if ($data->delete()) {
return $this->create('使用者刪除成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('使用者不存在,無法刪除', 204, []);
} else {
return $this->create('id 引數錯誤', 400, []);
}
}
}
但是,要注意一點,在實際的生產環境中,無論我們多麼想刪除資料庫裡面的資料,事實上我們都不會刪,因為我們受過專業的訓練(毒打)。
那麼,如何讓存在資料裡面的資料,看起來像是“被刪除”的樣子呢?
答案是增加一個 狀態欄位,如果一條資料的狀態欄位的值是 1,代表這是一條正常的記錄;如果是 -1 或者其它值,代表這是一條已經被刪除的記錄,沒有許可權的人是查不到這條記錄的。
由此,引申出web工程師第二準則:永遠不要刪除生產環境的資料。(除非你想搞破壞)
接下來是 Postman 除錯(就刪除我們剛剛建立的第 51 號使用者好了):
此時如果我們開啟資料庫,發現第 51 條記錄已經沒有了,再次提示,這只是在本地開發環境的學習過程,在生產環境中,任何與刪除有關的動作都是很危險的,一定要慎之又慎。
10. 修改資料 API
在原視訊中,是沒有這部分內容的,但是,出來混,要講信用,說了增刪改查工程師,就要增刪改查,一個都不能少。
以下是我通過自己的理解寫出來的,還是那就說話,如果有更好的寫法,請在評論區 show you code
檔案位置: app\Http\Controllers\UserControllers.php
編碼如下:
public function update(Request $request, $id)
{
// 接收資料
// 驗證資料
// 查詢使用者
// 如果使用者不存在
// 更新並返回資訊
$data = $request->all();
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
}
$user = User::find($id);
if (isset($user)) {
if ($user->update([
'name' => $request->name,
'password' => md5($request->password),
])) {
return $this->create('使用者更新成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('使用者不存在,無法更新', 204, []);
} else {
return $this->create('id 引數錯誤', 400, []);
}
}
}
程式碼思路請看註釋文字,以下是 Postman 除錯時間:
查詢第一個使用者的資訊如下:
然後呼叫api,修改 1 號使用者的 name 和 password 資訊:
最後,再次檢視,可以看到,已經修改成功:
至此,整個課程筆記已經結束。
因為之前的程式碼是分塊編寫並解釋,觀感並不是很好,所以在附錄部分,貼上 app\Http\Controllers\UserControllers.php
的完整程式碼,供大家參考,以免出錯。
附錄
完整的app\Http\Controllers\UserControllers.php
如下:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Auth\Events\Validated;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UserController extends ApiController
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// 資料獲取
// 返回資料
$data = User::select('id', 'name', 'email')->simplePaginate(10); // 簡單分頁
return $this->create('資料獲取成功', 200, $data);
// 資料獲取的其它寫法舉例
// 獲取全部可顯示欄位
// $data = User::get();
// 獲取指定欄位
// $data = User::select('id','name','email')->get();
// 獲取指定欄位並分頁
// $data = User::select('id','name','email')->paginate(10);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
// 接收資料
$data = $request->all();
// 資料驗證
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'email' => 'required|min:2|max:50|email',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
} else {
$newUser = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => md5($request->password),
]);
$newUser = User::select('id', 'name', 'email')->find($newUser['id']);
return $this->create('使用者建立成功', 200, $newUser);
}
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
// 獲取資料
// 資料存在 返回成功資訊
// 資料不存在
// 引數超出範圍導致資料不存在
// 引數型別錯誤導致資料不存在
$data = User::select('id', 'name', 'email')->find($id);
if (isset($data)) {
return $this->create('資料獲取成功', 200, $data);
} else {
if (is_numeric($id)) {
return $this->create('使用者不存在', 204, []);
} else {
return $this->create('id 引數錯誤', 400, []);
}
}
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
// 接收資料
// 驗證資料
// 查詢使用者
// 如果使用者不存在
// 更新並返回資訊
$data = $request->all();
$validator = Validator::make($data, [
'name' => 'required|min:2|max:50',
'password' => 'required|min:6|max:50',
]);
if ($validator->fails()) {
return $this->create($validator->errors(), 400);
}
$user = User::find($id);
if (isset($user)) {
if ($user->update([
'name' => $request->name,
'password' => md5($request->password),
])) {
return $this->create('使用者更新成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('使用者不存在,無法更新', 204, []);
} else {
return $this->create('id 引數錯誤', 400, []);
}
}
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
// 獲取資料
// 資料存在,刪除
// 資料不存在
// 引數超出範圍導致資料不存在
// 引數型別錯誤導致資料不存在
$data = User::find($id);
if (isset($data)) {
if ($data->delete()) {
return $this->create('使用者刪除成功', 200);
}
} else {
if (is_numeric($id)) {
return $this->create('使用者不存在,無法刪除', 204, []);
} else {
return $this->create('id 引數錯誤', 400, []);
}
}
}
}
完結,撒花,感謝閱讀。
本作品採用《CC 協議》,轉載必須註明作者和本文連結