Laravel 基本配置與 RESTful API 入門

Kion
36 min readJun 17, 2020

--

https://medium.com/@hosomikai/laravel-php-%E8%A7%A3%E6%B1%BA-env-%E5%8F%96%E5%87%BA%E7%9A%84%E5%80%BC%E7%82%BAnull-33a1aefa3d55

目次

1. .env 與 database.php 配置
2. Eloquent Model
3. Routes 與 Controller
4. Migrations
5. Seeding & Factories
6. Unit Test
7. 檔案參考

上篇把 Laravel 專案建立起來之後,現在就來進行環境配置與簡易的 API 吧

若還沒安裝好,可以參考下面的文章:

此次的目標是建立擁有 CRUD 功能的 RESTful API

什麼是 CRUD ?

CRUD 顧名思義是一種簡寫,意即:

C
rate: 新增

R
ead: 讀取

U
pdate: 更新

D
elete: 刪除

四種常見的 API

此次建立的 API 需要與資料庫的互動
因此在開始之前,請確認自己是否有安裝資料庫
我使用的是 MySQL 去搭配 Laravel
若還沒下載,可以點擊下面連結下載 MySQL 及其圖形化介面

Laravel 基本配置

首先請在 MySQL 先新增一個名為 test 的資料庫

.env 配置與 database.php 配置

確認 php artisan serve 指令可以順利連線後
就要開始配置資料庫了

.env

在專案建立時,應該會有一個 .env 以及 .env.expamle

.env.example 檔是 .env 檔的空白檔的概念
如果在專案內沒有發現 .env ,複製 .env.example 更改檔名即可

由於是練習,我們只需配置部分區塊:

APP_NAME=Laravel (專案的名稱)
APP_ENV=local (專案開發的環境,local / staging)
APP_KEY= (APP KEY)
APP_DEBUG=true (提供在瀏覽器中顯示詳細的錯誤訊息來進行debug)
APP_URL=http://localhost(專案網址,EX. http://example.com,使用方法url()時便可取得該網址)

LOG_CHANNEL=stack

DB_CONNECTION=mysql (使用的資料庫)
DB_HOST=127.0.0.1 (資料庫主機位置)
DB_PORT=3306 (資料庫的埠號)
DB_DATABASE=test (資料庫名稱)
DB_USERNAME= (資料庫帳號)
DB_PASSWORD= (資料庫密碼)

如果是透過 Laravel new (專案名稱) 的方式建立專案,通常 APP_KEY 已經被塞好值了
但如果 APP_KEY 沒有值,則必須產生 APP_KEY
APP_KEY 用作加密 session , password 以及其他重要資料,沒有設定的話,這些資料會有安全上的問題
且執行 php artisan serve 也會跳出警示

要產 Key 也十分容易

php artisan key:generate

下完指令,他會自動生成 key 直接更新在 .env 檔,不需複製貼上

database.php

'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'test (資料庫名稱)'),
'username' => env('DB_USERNAME', '(資料庫帳號)'),
'password' => env('DB_PASSWORD', '(資料庫密碼)'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4 (資料庫編碼)',
'collation' => 'utf8mb4_unicode_ci (資料庫定序)',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],

創建 CRUD 功能 API

建立好資料庫連線後,先來了解一下 Laravel 的資料傳輸的過程

https://code.tutsplus.com/zh-hans/tutorials/build-a-react-app-with-laravel-restful-backend-part-1-laravel-5-api--cms-29442
  1. 瀏覽器發出請求
  2. Routes 從網址判斷要呼叫哪個 Controller 進行邏輯處理
  3. 與 Model 互動,取出或更改資料
  4. Eloquent 與 Database 互動,更改或取出資料
  5. 結果回傳至 Controller 處理
  6. Controller 將結果回傳至指定頁面

剛剛我們已經完成資料庫的配置
從上圖的流程我們可以發現
若要完成一個 API ,我們接下來還需配置:

  1. Eloquent Model
  2. Routes
  3. Controller

但在執行其他動作以前
我們先來假想我們要操作的情境與動作

那這次我所設定的情境就是:
針對使用者的資料進行讀取、新增、修改、刪除

因此我們必須創建一個資料表,裝使用者的資料
我設定的資料庫 Schema 如下:

資料表名稱:userData欄位       型態userId    int
userName varchar(45)
account varchar(45)
pw varchar(45)
email varchar(45)

我們有兩種方式可以完成此動作

  1. SQL
CREATE TABLE userData(
userId int NOT NULL AUTO_INCREMENT,
userName varchar(45) NOT NULL,
account varchar(45) NOT NULL,
pw varchar(45) NOT NULL,
email varchar(45) NOT NULL,
PRIMARY KEY (userId)
)

2. Migrations

Laravel 有提供一個工具叫做 Migrations
Migrations 他的用途很多,像是:同步專案的資料庫結構、資料庫版控、測試….等等
透過 Artisan 指令,不需操作 SQL,直接建立一張客製化的資料表

如果是初學且有 SQL 的基礎
可以先不用給自己壓力這麼大,馬上學習 Migrations
後面腳本測試也會講到

若覺得目前吸收還可以,或是沒有學過 SQL 語法
可以試著用 Migrations 省去 SQL ,他的操作並沒有很困難
直接跳轉到測試主題的 Migrations

Model

如果還記得上面那張圖的話
剛剛我們已經配置好資料表,準備要開始配置 Eloquent Model 了!

https://code.tutsplus.com/zh-hans/tutorials/build-a-react-app-with-laravel-restful-backend-part-1-laravel-5-api--cms-29442

在配置 Model 前,先來了解什麼是 Eloquent
Eloquent 為 Laravel 官方所提供的 ORM 框架

Object-Relational Mapping (ORM) 對象關係映射

ORM 提供了一條橋樑,將後端的物件型資料和資料庫中的關係型的資料通過這個橋樑來相互轉化

他的概念就是:
透過建立一個物件將物件對應到資料庫結構,往後只需操作物件就可以對資料庫的資料進行讀取、新增、修改、刪除…..等

有了 ORM ,就不用再下一堆 SQL
只需簡單的操作實體對象的屬性和方法
且不同資料庫的 SQL 寫法會有所不同
因此,要轉移至其他資料庫服務,也不用耗費太高的轉換成本

了解何謂 ORM 後,我們就要來建立與我們資料表對映的物件

指令:

php artisan make:model UserInfo

接著在 app/UserInfo.php 進行配置

class UserInfo extends Model
{
protected $table = 'userData'; // 資料表名稱
protected $primaryKey = 'userId'; // 主鍵
public $timestamps = false;
protected $fillable =
['userId','userName','account','pw','email'];
}
  • public $timestamps = false : 因為我們沒有設定 created_atupdated_at 的欄位,不需要時間戳記
  • $fillable :調用 create() update() 時,可以大量新增、修改的欄位
    切記一定要在 Model 增添這個屬性!
    如果盲目的存入使用者輸入,使用者可以隨意的修改任何以及所有模型的屬性,可能會造成嚴重的安全隱患
    因此,所有的 Eloquent 模型預設會防止批量賦值,所以要設定這個變數去允許這個欄位可以被新增資料

沒有增添這個屬性,新增、修改的 API 將無法作用

fillable 或 guarded 屬性

不只 fillable 屬性還可以使用另一個屬性 guarded
一樣的目的、不同的意義

  • fillable:設定可以大量新增的欄位(白名單)
class User extends Model {protected $fillable = ['userId','userName','account','pw','email'];}
  • guarded:設定需要被保護的欄位(黑名單)
class User extends Model {    protected $guarded = [‘uuid’, ‘pw’];}

這樣我們的 Model 就算是建構完成了!

不過還有一個重點
有了資料庫、有了 Model
但因為是練習,不會有真實的資料進來
因此我們還欠缺可以操作的資料

要新增資料有兩種方法:

  1. SQL
INSERT INTO `userData`(`userId`, `userName`, `account`, `pw`, `email`) 
VALUES (1,'aaa','aaabbb','aaabbbccc','aaa@aaaaa'),
(2,'bbb','bbbccc','bbbcccddd','bbb@bbbbb'),
(3,'ccc','cccddd','cccdddeee','ccc@ccccc')

2. Database Seeding & Factories

Laravel 提供一種方法叫做 Seeding
透過 Artisan 指令,就可以依照指定的方法生成假資料插入資料表欄位
且搭配 Factories 可以指定新增資料筆數,方便快速,常用於測試環境

如果是初學還不想給自己這麼大的學習壓力
可以先用 SQL 新增三筆資料
後面測試也會講到 Seeding

但如果想嘗試的話,他的操作也沒有很困難
可以直接跳轉到測試主題的 Seeding

Routes 與 Controller

完成 Model 後就可以藉著我們的重頭戲 Routes 和 Controller 了

https://code.tutsplus.com/zh-hans/tutorials/build-a-react-app-with-laravel-restful-backend-part-1-laravel-5-api--cms-29442

Controller

首先,先來設定 Controller
Controller 負責處理 Model 的數據,將相關的請求處理邏輯分組為一個類

在生成 Controller 時有兩種方式,他的差異僅在幫你生成的 function 模板

  1. --resource

生成 index() show() store() update() destory() create() edit()

php artisan make:controller api/UserInfoController --resource

2. --api

生成 index() show() store() update() destory()
為你省略「create」及「edit」的方法

php artisan make:controller api/UserInfoController --api
  • index() :抓取所有資料的列表
  • show() :抓取指定 id 的資料
  • store() :新增資料
  • update() :更新資料
  • destory() :刪除資料
  • create() :抓取新增的頁面
  • edit() :抓取編輯的頁面

我還不清楚 create()edit()
根據 官方文件 他們都是用 GET 為主

且這次我也只需要基本的 API 我就直接使用 --api 的指令了 XD
如果可以告訴我他們是用在什麼情境我會很感激的

因為要寫的是 API
我也特別新增一個名叫 app/HTTP/Controller/api/ 的資料夾區隔
但也可以都放在 app/HTTP/Controller
只需要在打指令下參數時,更改檔案路徑即可

  • app/HTTP/Controller
php artisan make:controller UserInfoController --api
  • app/HTTP/Controller/api/
php artisan make:controller api/UserInfoController --api

建立好檔案後,就可以開始寫 function 的內容了
透過 調用 Model 的方法,獲取、更新資料,並根據 CRUD 四種方式,配置相對應的 function

app/HTTP/Controller/api/UserInfoController.php

根據 routes 傳來的參數不同,可以分成兩種寫法:

  1. 一般參數
<?php

namespace
App\Http\Controllers\api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\UserInfo;

class UserInfoController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return response()->json(UserInfo::all(), 200);
}

/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$userInfo = UserInfo::create($request->all());

return response()->json($userInfo, 201);
}

/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
return response()->json(UserInfo::find($id), 200);
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$userInfo = UserInfo::findOrFail($id);
$userInfo->update($request->all());

return response()->json($userInfo, 200);
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
UserInfo::find($id)->delete();

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

2. 構造函數注入 Constructor Injection

<?php

namespace
App\Http\Controllers\api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\UserInfo;

class UserInfoController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return response()->json(UserInfo::all(), 200);
}

/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$userInfo = UserInfo::create($request->all());

return response()->json($userInfo, 201);
}

/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(UserInfo $userInfo)
{
return response()->json($userInfo, 200);
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, UserInfo $userInfo)
{
$userInfo->update($request->all());

return response()->json($userInfo, 200);
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(UserInfo $userInfo)
{
$userInfo->delete();

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

Routes

我們寫好了負責資料處理的 Controller
接下來就要配置我們的 Routes

Routes 會根據請求的路徑和 HTTP Verb 的不同
調用對應的 Controller 的某個 Function

在 Laravel 中 Routes 有兩種: routes/web.phproutes/api.php

一開始我也是很困惑為什麼也有兩個 Routes
後來我才知道他其實也是區分 API 和一般頁面的概念

routes/web.php

如果點進 routes/web.php 可以看見以下配置:

Route::get('/', function () {
return view('welcome');
});

也就是說,當啟動伺服器,我輸入我的網址(http://127.0.0.1:8000)時
我的根目錄就是返回 welcome.bladephp 這個檔案
它位於 resources/views/

點進檔案仔細一看,他其實是一個 HTML 加上一點邏輯判斷的檔案
這樣的模板成為 Blade
但今天的重點不是他就簡單帶過了

另外,若要返回 view (Blade 模板),還有一個更簡便的語法

Route::view('/', 'welcome');

routes/api.php

如果只是檔名不同也太小看他們的差異了
若將路徑配置在 api.php
訪問的路徑將更改為: http://127.0.0.1:8000/api/…

由於我們寫的是 API ,就在 api.php 配置了!

不光如此,配置 routes 有兩種寫法,基本款和進階版

api.php 基本配置

根據剛剛 Controller 接的參數不同,routes 會有兩種寫法:

  1. 一般參數
Route::get(‘user’, ‘api\UserInfoController@index’);
Route::get(‘user/{id}’, ‘api\UserInfoController@show’);
Route::post(‘user’, ‘api\UserInfoController@store’);
Route::put(‘user/{id}’, ‘api\UserInfoController@update’);
Route::delete(‘user/{id}’, ‘api\UserInfoController@destroy’);

2. 構造函數注入

Route::get(‘user’, ‘api\UserInfoController@index’);
Route::get(‘user/{userInfo}’, ‘api\UserInfoController@show’);
Route::post(‘user’, ‘api\UserInfoController@store’);
Route::put(‘user/{userInfo}’, ‘api\UserInfoController@update’);
Route::delete(‘user/{userInfo}’, ‘api\UserInfoController@destroy’);

第一個參數是對應的路徑,後面有 { } 代表傳入的參數
在 Controller 中,function 會接到參數進行後續的操作

第二個參數是對應的 Controller
若一開始你的 Controller 配置在 api/ 資料夾內,請記得補好路徑
後面的 @ 接的是 Controller 內要呼叫的方法名稱

api.php Resource Controllers 配置

說是進階版,不如說是懶人版
只需單行代碼就能將常用的 CRUD API 分配給 Controller

Route::apiResource('user', 'api\UserInfoController');

一樣,若 Controller 配置在 api/ 資料夾內,請記得補好路徑

但這裡有一個地方要特別注意!

Controller 內的 function 預設是接一般參數,並不是使用構造函數注入

所以記得要檢查一下

這個寫法的好處就是我們把原本的五行縮減成一行
如果沒有特別更改路徑
他的路徑訪問方式,已經被規定在文件上了

我們已經完成了 API
接下來就可以使用像是 Postman 等方式去測試我們的 API 是否成功了!

配置資料表、假資料與撰寫測試腳本

寫好我們的 API 後,每次要一個個用 Postman 去測試是否成功
實在是太費功夫
且,若今天我們要將自己的專案交由他人下載、測試
資料庫中的 Schema 和 測試資料,難道要請對方自己建立嗎?

因此今天要使用的就是 Laravel 的 Migrations 和 Factories & Seeding
快速建立測試的資料表 Schema 和測試用的假資料

Migrations

Migrations 可以說是資料庫的版控工具
他會產生一個時間戳記的檔案,紀錄當前資料庫的結構
且分享此檔案可以與協作人員同步目前的 Schema

他可以生成一個目前資料表的基本欄位名稱、欄位型別等等
只要執行指令,不用下 SQL
直接幫我們在綁定的資料庫創建一張基本的資料表
因此,在撰寫測試腳本時,Migrations 是很重要的
沒有 Migrations 就無法在測試環境建立資料表

當然不僅是建構新資料表
若資料表有更動的話,下指令就會產生一個有時間戳記的檔案
也因為他都有記錄,所以也可以退回到某一版的資料庫結構
是個十分方便的工具

在 Laravel 新增一張資料表也十分簡單,只要下指令:

php artisan make:migration create_user_infos_table --create="userData"

Migration 檔名最前面的時間是依照你建立 Migration 的時間自動產生
所以每次產生的檔名皆會不同
在後面加了 --create 的參數可以告訴 Migration,我們要做建立 userData 資料表的動作
其中 create_user_infos_table 為 class 名稱
後面的參數 --create="userData" 則是綁定指定資料表

接著我們就可以開始修改 database/migrations 的檔案了

  • up() 為下指令時會執行的動作
  • down() 為退版時會執行的動作

因此 up() & down() 通常是相反的動作,例如:

  • 建立新資料表;刪除資料表
  • 新增欄位;刪除欄位

撰寫欄位時,可以參考 Laravel 提供的 欄位資料型態 方法設定資料型態

class CreateUserInfosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('userData', function (Blueprint $table) {
$table->increments('userId');
$table->string('userName');
$table->string('account');
$table->string('pw');
$table->string('email');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('userData');
}
}

完成後就可以執行 migrations

php artisan migrate

如此一來就會直接更動到資料表的結構
如果配置的是正式環境的資料庫,這會是一個危險的指令
雖然可以 rollback,但失去的資料是回不來的
一定要小心使用

Migrations 指令合集

版本紀錄指令

  • 創建一張資料表
php artisan make:migration create_user_infos_table --create=userData
  • 異動欄位
php artisan make:migration add_votes_to_users_infos_table --table=userData

執行指令

php artisan migrate

退版指令

  • 向後退一版
php artisan migrate:rollback
  • 向後退到指定版數:--step=5 退到前五版
php artisan migrate:rollback --step=5

返回預設值

  • 丟掉所有資料表
php artisan migrate:reset
  • 返回所有動作,退到最初版,並執行 migrations
php artisan migrate:refresh
  • 退到指定版數,並執行 migrations
php artisan migrate:refresh --step=5
  • 丟棄所有資料表,執行 migrations
php artisan migrate:fresh

Seeding & Factories

建立好 Migrations 後,就要開始準備測試的假資料

Seeding

Seeding 是 Laravel 快速插入假資料的工具
透過自訂的規則生成假資料,

Seeding 有兩種配置方式:

  1. 直接將生成規則寫在 database/seeds/DatabaseSeeder.php
  2. 將不同的資料表的假資料規則拆分在不同的檔案,再從 DatabaseSeeder 調用

從上述比較可以發現:
使用方法二可以將不同的資料表假資料規則拆分,檔案就會比較小且有條理
因此我是使用這樣的配置,直接創建一個專屬 UserInfo 的 Seeding

指令:

php artisan make:seeder UserInfosTableSeeder

UserInfosTableSeeder

<?php

use
Illuminate\Database\Seeder;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;

class UserInfosTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('userData')->insert([
'userName' => Str::random(10),
'account' => Str::random(10),
'email' => Str::random(10).'@gmail.com',
'pw' => Hash::make('password'),
]);
}
}

寫好 Seeder 後,請記得下一個指令

composer dump-autoload

為什麼要下這個指令呢?

因為 database 文件夾使用 classmap 來做加載的
所以只有在打了 composer dump-autoload 之後 composer 才會更新 autoload_classmap 的內容

資料來源:https://learnku.com/php/t/1002/deep-composer-autoload

然後執行:

php artisan db:seed

或是單執行

php artisan db:seed --class=UserInfosTableSeeder

如此一來,他就會在我們配置的資料庫插入假資料
若你配置的是正式環境的資料庫,他其實是一個危險的指令,會洗掉所有的資料
務必要小心使用

另外,若想要刷新清空資料庫,再重新建立資料表並插入假資料
可以使用 Migration 的指令加 --seed

php artisan migrate:fresh --seed

Factories

在 Seeder 裡,我們的邏輯是:
在每個的資料型態欄位內,用相對應的資料型態,取亂數塞值
這是一個好方法,但缺乏演示性
當我們想要取得使用者名稱跟帳號時,由於都是亂數塞值,根本分不清差別

使用 Factories 可以改善這樣的情形
利用Faker實例,在 return 內編寫隨機建立結構化的假資料
且我們還可以指定生成的資料筆數

亂數塞值

使用 Factories

指令:

php artisan make:factory UserInfoFactory --model=UserInfo

--model 來綁定模型

database/factories/UserInfoFactory.php

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\UserInfo;
use Faker\Generator as Faker;

$factory->define(UserInfo::class, function (Faker $faker) {
return [
'userName' => $faker->name,
'email' => $faker->unique()->safeEmail,
'pw' => $faker->password,
'account' => $faker->userName
];
});

他的使用方法就是,將你的欄位名稱作為鍵值,將 faker 中的屬性賦予給他
更多 faker 的屬性請參考 這個連結

有了 Migrations Seeding Factories,我們可以很快地建立測試環境的假資料
以供我們在撰寫 API 時,不需要再下 SQL 塞資料測試 API 功能是否正常運作

且這也提供我們運行測試腳本時
能夠快速建立相對應的資料表和假資料,以供測試

Unit Test

若我們開發一個功能,要一直手動用 Postman 等方法去測試 API
其實是很費功夫的
API 要求的格式都一樣,所以這些應該可以交由程式執行
這也就是單元測試的概念

在撰寫測試腳本前,首先要先配置好我們的運行測試時的資料庫

在測試環境,我們使用的是 MySQL
但在運行測試腳本時,我們操作的資料庫就不再使用 MySQL 了,而是 SQLite
讓我們的測試更輕量快速

config/database.php

'connections' => [

'sqlite' => [
....
'database' => ':memory:',
....
],
.......
]

phpunit.xml

接著在 XML 檔也配置好我們要連接的資料庫

<php>
....
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
....
</php>

composer.json

配置好 phpunit.xml 後,將他加入 composer 的指令

"scripts": {
"test" : [
"vendor/bin/phpunit"
],
...
},

接著建立測試檔案

php artisan make:test UserInfoTest

tests/Feature/UserInfoTest

<?php

namespace
Tests\Feature;

use App\UserInfo;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserInfoTest extends TestCase
{
/**
* A basic feature test example.
*
* @return void
*/
use WithFaker;

public function test()
{
// Return View
$response = $this->get('/');

$response->assertStatus(200);

// Get
$response = $this->call('GET', '/api/user');

$this->assertEquals(200, $response->getStatusCode());

// Get userId = 1
$response = $this->call('GET', '/api/user/1');

$this->assertEquals(200, $response->getStatusCode());

// Post

$payload = factory(UserInfo::class)->make()->toArray();

$response = $this->call('POST', '/api/user', $payload);

$this ->assertEquals(201, $response->getStatusCode());

// Put

$payloadPut = [
'userId' => 1,
'userName' => $this->faker->name,
'account' => $this->faker->userName,
'pw' => $this->faker->password,
'email' => $this->faker->unique()->safeEmail
];

$response = $this->call('PUT', '/api/user/1', $payloadPut);

$this ->assertEquals(200, $response->getStatusCode());

// Delete

$response = $this->call('DELETE', '/api/user/1');

$this ->assertEquals(204, $response->getStatusCode());
}
}

其中, POST 和 PUT 的測試因為要有資料,會比 GET、DELETE 還要再麻煩些

這時有兩種方法,一種是自己寫假資料更新上去,另一種則是用 Factories

POST

直接使用 Factories
按照規則生成資料,並轉成陣列儲存在變數之中送出

$payload = factory(UserInfo::class)->make()->toArray();$response = $this->call('POST', '/api/user', $payload);

PUT

引入 use Illuminate\Foundation\Testing\WithFaker;
如此一來,就可以透過$this -> faker來操作 Faker

因此我預設我要更改的資料就是 userId 1 的資料
宣告一個陣列,按照規則生成資料送出

$payloadPut = [
'userId' => 1,
'userName' => $this->faker->name,
'account' => $this->faker->userName,
'pw' => $this->faker->password,
'email' => $this->faker->unique()->safeEmail
];

$response = $this->call('PUT', '/api/user/1', $payloadPut);

TestCase.php

撰寫完測試腳本後,接下來就是配置 TestCase.php

我們有了資料表、假資料、測試方法
但在測試前,我們還少執行建立資料表和假資料的指令

TestCase.php
引入 use Illuminate\Foundation\Testing\DatabaseMigrations;
Laravel 提供了簡潔的 DatabaseMigrations,它會自動幫你處理 Migrations

接著引入 use Illuminate\Support\Facades\Artisan;
在觸發 setup() 時,我們直接調用 Artisan 中 Seeding 的指令塞入假資料

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Artisan;

abstract class TestCase extends BaseTestCase
{
use CreatesApplication, DatabaseMigrations;

public function setUp()
{
parent::setUp();
Artisan::call('db:seed');
}
}

如此一來,我們的測試腳本就大功告成啦!

接著只需要在終端機上輸入: php artisan test
就會開始運行測試腳本了!

檔案參考

花了兩個禮拜摸索,終於把 API 寫出來
其中我覺得最累人的莫過於配置了
因為一樣的東西有好幾種方法看你的需求,兩種都對
只是關乎檔案整不整潔

因此,為了讓新手們更加快速上手
我將我練習的檔案開源,附在這給大家參考

希望可以幫助到更多人,大家都能順利上手 Laravel !

拍個手讓我知道,這個文章對你們有幫助 ♥(´∀` )人

參考資料

  1. Laravel 官方文件
  2. Laravel 5 學習筆記
  3. Laravel API Tutorial: How to Build and Test a RESTful API
  4. 30天快速上手Laravel
  5. 從零開始的Laravel RESTful API
  6. 後端PHP+Laravel — 新手實戰日記
  7. Laravel + Nuxt.js 踩坑全紀錄
  8. Laravel 建立 RESTful API

--

--

Kion

程式就是利用自動化與排程的特性解決問題 文章分類總覽: https://hackmd.io/@Kion/SyvyEks0L