เบื้องหลัง API Artisan: สร้าง Laravel API ที่นักพัฒนาอยากใช้จริง

โดย CyberMAN


PHP Code Mania · Laravel API

เบื้องหลัง API Artisan: สร้าง Laravel API ที่นักพัฒนาอยากใช้จริง

ตั้งแต่ออกแบบ endpoint แรก ไปจนถึง versioning และการเขียนเทสต์ — เคล็ดลับที่ทำให้ API ของคุณไม่ใช่แค่ "ใช้งานได้" แต่เป็น API ที่ทีมอื่นเปิดเอกสารแล้วยิ้ม

~/projects/api-artisan
$ php artisan make:controller UserController --api
INFO  Controller [app/Http/Controllers/UserController.php] created successfully.

$ php artisan make:resource UserResource
INFO  Resource [app/Http/Resources/UserResource.php] created successfully.

# เริ่มต้นเหมือนช่างฝีมือ: เตรียมเครื่องมือก่อนลงมือ

คำว่า Artisan ใน Laravel ไม่ได้แปลว่า "เครื่องมือบรรทัดคำสั่ง" เพียงอย่างเดียว แต่มันสะท้อนปรัชญาของเฟรมเวิร์กนี้ทั้งหมด นั่นคือ การเขียนโค้ดควรเป็นงานฝีมือที่ประณีต ไม่ใช่แค่โค้ดที่ "รันผ่าน" แล้วจบ และไม่มีที่ไหนที่ปรัชญานี้สำคัญเท่ากับตอนที่คุณกำลังออกแบบ API เพราะ API ที่คุณสร้างวันนี้ จะกลายเป็นสัญญา (contract) ที่ทีม frontend, แอปมือถือ หรือแม้แต่ระบบภายนอกต้องพึ่งพาไปอีกหลายปี

บทความนี้เขียนขึ้นสำหรับนักพัฒนาที่คุ้นเคยกับ CodeIgniter 4 หรือเพิ่งเริ่มจับ Laravel และอยากเข้าใจว่า "API ที่ดี" ในมุมมองของ Laravel ควรหน้าตาเป็นอย่างไร เราจะไล่ตั้งแต่การวางแผน ไปจนถึงเรื่อง authentication, validation, performance และการเขียนเทสต์ — ครบทุกขั้นตอนที่ทำให้ API ของคุณ "พร้อมใช้งานจริง" ไม่ใช่แค่ดีโม

01

วางแผนก่อนเขียนโค้ดสักบรรทัด

นักพัฒนามือใหม่จำนวนมากเปิด editor แล้วเริ่มเขียน route ทันที แต่ช่างฝีมือที่ดีจะร่างแบบก่อนลงมือ ก่อนเขียนโค้ด ให้ถามตัวเองสามข้อ: API นี้มีไว้เพื่ออะไร, resource อะไรบ้างที่จะเปิดให้เข้าถึง และใครคือผู้ใช้งานปลายทาง (mobile app, SPA หรือระบบภายนอก)

เมื่อตอบคำถามเหล่านี้ได้แล้ว ให้ออกแบบ endpoint ตามหลัก RESTful คือยึด resource เป็นหลักและใช้ HTTP method สื่อความหมายของการกระทำ เช่น GET /api/users สำหรับดึงรายการ และ POST /api/users สำหรับสร้างใหม่ แทนที่จะตั้งชื่อ endpoint แบบ /api/getAllUsers ซึ่งไม่ตรงตามแบบแผนที่นักพัฒนาส่วนใหญ่คุ้นเคย

เคล็ดลับ: เขียนเอกสาร API ไว้ตั้งแต่ก่อนเริ่มโค้ดจริง แม้จะเป็นแค่โน้ตสั้น ๆ ก็ช่วยให้ทีมเห็นภาพตรงกันก่อนที่จะแก้โครงสร้างทีหลัง ซึ่งมีต้นทุนสูงกว่ามาก

02

ใช้ Resource Controller จัดระเบียบ CRUD

Laravel มีคำสั่งสร้าง controller สำหรับ API โดยเฉพาะ ซึ่งจะมาพร้อมเมธอดมาตรฐานครบทั้ง 5 ตัวสำหรับ CRUD โดยไม่มีเมธอดสำหรับแสดงฟอร์ม (เพราะ API ไม่ต้องการ view)

terminal
// สร้าง controller แบบ API (ไม่มี create/edit form)
php artisan make:controller UserController --api

คำสั่งนี้จะสร้างเมธอด index, store, show, update, destroy ให้พร้อมใช้ จากนั้นคุณแค่เติม logic เข้าไป โดยให้แต่ละเมธอดทำหน้าที่เดียวให้ชัดเจน ไม่ปนกัน

UserController.php
public function index() {
    return UserResource::collection(User::paginate(10));
}

public function show(User $user) {
    return new UserResource($user);
}

public function store(StoreUserRequest $request) {
    $user = User::create($request->validated());
    return new UserResource($user);
}
03

แปลง Model เป็น JSON ด้วย API Resource

ปัญหาคลาสสิกของมือใหม่คือการ return $user; ตรง ๆ จาก Eloquent ซึ่งจะส่งทุกคอลัมน์ในตาราง รวมถึง password hash หรือ token ที่ไม่ควรหลุดออกไปด้วย API Resource คือชั้นที่ทำหน้าที่ "คัดและจัดรูป" ข้อมูลก่อนส่งออกไปเป็น JSON

terminal
php artisan make:resource UserResource
UserResource.php
public function toArray($request) {
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'joined_at' => $this->created_at->format('Y-m-d'),
    ];
}

ข้อดีคือเมื่อโครงสร้างฐานข้อมูลเปลี่ยน คุณแก้แค่ที่เดียวในไฟล์ Resource โดยที่ฝั่ง client ไม่รู้สึกถึงผลกระทบเลย

04

Validate ทุกครั้งด้วย Form Request

อย่าไว้ใจข้อมูลที่ส่งเข้ามาจาก client เด็ดขาด ไม่ว่าจะเป็นแอปมือถือของทีมคุณเองก็ตาม Laravel แนะนำให้แยก logic การตรวจสอบข้อมูลออกจาก controller ไปไว้ในคลาส Form Request โดยเฉพาะ เพื่อให้ controller อ่านง่ายและ validation rule นำกลับมาใช้ซ้ำได้

terminal
php artisan make:request StoreUserRequest
StoreUserRequest.php
public function rules() {
    return [
        'name'  => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
    ];
}
05

ยืนยันตัวตนด้วย Sanctum

สำหรับ API ที่ให้บริการ SPA หรือแอปมือถือ Laravel Sanctum คือตัวเลือกที่เบาและตั้งค่าง่ายกว่า OAuth เต็มรูปแบบ เหมาะกับโปรเจกต์ส่วนใหญ่ที่ไม่ได้ต้องการระบบสิทธิ์ซับซ้อนระดับองค์กร

terminal
composer require laravel/sanctum
routes/api.php
Route::middleware(['auth:sanctum', 'throttle:60,1'])->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
});

การห่อ route ไว้ใน middleware group แบบนี้ ทำให้คุณจัดการ authentication และ rate limiting ของหลาย endpoint พร้อมกันได้จากจุดเดียว ไม่ต้องเขียนซ้ำในทุกเมธอด

06

คุม Performance ด้วย Pagination และ Eager Loading

API ที่ตอบกลับข้อมูลทั้งตารางในครั้งเดียวคือระเบิดเวลา เพราะเมื่อข้อมูลในฐานข้อมูลโตขึ้น response time จะยิ่งช้าลงเรื่อย ๆ ใช้ paginate() เพื่อจำกัดจำนวนต่อหน้าเสมอ

UserController.php
// ดึง user พร้อม posts ในคำสั่งเดียว แทนการ query วนลูป
$users = User::with('posts')->paginate(10);

การเรียก with('posts') คือ eager loading ที่ช่วยแก้ปัญหา N+1 query ซึ่งเป็นสาเหตุอันดับต้น ๆ ที่ทำให้ API ของมือใหม่ช้าโดยไม่รู้ตัว เพราะถ้าไม่ใส่ Laravel จะยิง query แยกไปดึง posts ของ user แต่ละคนทีละแถว

07

ตอบ Error ให้สม่ำเสมอ และเปิด CORS อย่างปลอดภัย

ฝั่ง client จะเขียนโค้ดจัดการ error ได้ง่ายขึ้นมาก ถ้า API ของคุณตอบกลับ error format เดียวกันทุกครั้ง ไม่ใช่บางจุด throw exception เป็น HTML บางจุดเป็น JSON ปนกัน Laravel มีระบบ exception handler กลางที่ช่วยควบคุมเรื่องนี้ได้ในจุดเดียว

ส่วนเรื่อง CORS หากต้องเปิดให้ frontend จากโดเมนอื่นเรียก API ได้ ให้ตั้งค่าผ่านไฟล์ config/cors.php โดยควรระบุโดเมนที่อนุญาตให้ชัดเจน แทนที่จะเปิดกว้างด้วย '*' ในระบบที่ใช้งานจริง เพราะนั่นเท่ากับเปิดให้เว็บไซต์ใดก็ได้เรียก API ของคุณ

08

Version API ไว้ตั้งแต่วันแรก

วันหนึ่งคุณจะต้องเปลี่ยนโครงสร้าง response แน่นอน ไม่ว่าจะเพิ่มฟิลด์หรือลบฟิลด์ที่ไม่ใช้แล้ว การมี version ใน path ตั้งแต่เริ่มต้น ช่วยให้คุณปล่อยเวอร์ชันใหม่ได้โดยไม่ทำให้แอปเวอร์ชันเก่าที่ยังเรียก API อยู่พังกะทันหัน

routes/api.php
Route::prefix('v1')->group(function () {
    Route::get('/users', [UserController::class, 'index']);
});
09

เขียน Test ไว้ดักก่อนโค้ดพัง

Laravel มีเครื่องมือทดสอบ API ในตัวที่ใช้งานง่ายมาก แค่ยิง request จำลองแล้วตรวจสอบ response ที่ได้ การมีเทสต์เพียงไม่กี่เคสสำหรับ endpoint สำคัญ ช่วยให้คุณกล้า refactor โค้ดในอนาคตโดยไม่ต้องนั่งทดสอบมือทุกครั้ง

UserApiTest.php
public function test_user_can_register() {
    $response = $this->postJson('/api/register', [
        'name'  => 'CyberMan',
        'email' => 'dev@example.com',
    ]);

    $response->assertStatus(201);
}
10

ปิดท้ายด้วยเอกสาร API

API ที่ไม่มีเอกสาร คือ API ที่ทีมอื่นกลัวจะใช้ แพ็กเกจอย่าง l5-swagger ช่วยให้คุณเขียนคอมเมนต์รูปแบบ OpenAPI ไว้เหนือแต่ละเมธอด แล้วระบบจะ generate หน้าเอกสารแบบ interactive ให้อัตโนมัติ ทำให้นักพัฒนาฝั่งอื่นทดลองยิง request ได้จากเบราว์เซอร์โดยไม่ต้องถามคุณซ้ำ ๆ

สรุปเช็กลิสต์: 8 เรื่องที่ API ของคุณควรมี

หัวข้อสิ่งที่ควรทำเครื่องมือ/แพ็กเกจ
โครงสร้าง endpointยึดหลัก RESTful ตาม resource และ HTTP methodroute:api
รูปแบบข้อมูลส่งออกใช้ Resource คัดและจัดรูป JSON เสมอmake:resource
ตรวจสอบข้อมูลขาเข้าแยก rule ไว้ใน Form Requestmake:request
การยืนยันตัวตนใช้ token-based auth ที่เบาและพอดีกับงานlaravel/sanctum
จำกัดการเรียกใช้ตั้ง rate limit ป้องกัน abusethrottle middleware
ความเร็วpaginate ทุก list และ eager load ความสัมพันธ์with() / paginate()
ความเข้ากันได้ย้อนหลังใส่ version ใน path ตั้งแต่ต้นRoute::prefix
ความมั่นใจในการแก้โค้ดเขียนเทสต์ครอบ endpoint สำคัญpostJson()

สรุป: API ที่ดีคืองานฝีมือ ไม่ใช่ของสำเร็จรูป

ทั้งหมดนี้ไม่ใช่กฎตายตัวที่ต้องทำให้ครบในวันแรก แต่เป็นแนวทางที่ค่อย ๆ เก็บเพิ่มได้ทีละข้อ เริ่มจาก Resource Controller และ API Resource ก่อน เพราะสองตัวนี้จะวางรากฐานให้โค้ดอ่านง่าย จากนั้นค่อยเติม validation, authentication และ rate limiting เข้าไปตามความจำเป็นของโปรเจกต์

สำหรับใครที่คุ้นเคยกับ CodeIgniter 4 อยู่แล้ว แนวคิดเรื่อง resource-based routing, การแยก validation ออกจาก controller หรือการ version API ก็นำไปปรับใช้กับ CI4 ได้เช่นกัน เพียงแค่ syntax และชื่อคลาสจะต่างกันไปตามแต่ละเฟรมเวิร์ก แก่นของหลักการยังเหมือนเดิม