Devfavor

Back

Laravel API Resource Patterns - ยกระดับการจัดการ Response ให้ทรงพลังBlur image

หากเราต้องการเขียน API ด้วย Laravel ตัว framework ของ Laravel เองก็มีเครื่องมืออำนวยความสะดวกให้เราใช้อยู่แล้วนั่นก็คือ API Resource ซึ่งทำให้เราสามารถจัดการกับ API response ได้อย่างง่ายดาย

แต่เมื่อระบบของเราใหญ่ขึ้น มีความซับซ้อนขึ้น รวมถึงความสัมพันธ์ระหว่าง Model เองก็ตาม การใช้ Laravel API Resource โดยปกติอาจจะไม่เพียงพอต่อความต้องการ จนทำให้โค้ดเกิดความซับซ้อนขึ้นได้

บทความนี้จะพาคุณมาทำความรู้จักกับการใช้งาน API Resource ร่วมกับ design pattern อื่น ๆ ที่มักพบในการเขียน Laravel เพื่อให้ API response ของเรามีความยืดหยุ่นและทรงพลังมากยิ่งขึ้น

🎨 Presenter / Transformer ตัวช่วยแปลงค่า แยก logic ให้ชัดเจน#

บางครั้งใน API Resource ที่เขียนอาจไม่ได้มีแค่การส่งค่าเพียงอย่างเดียว แต่ยังมี business logic แฝงอยู่ใน response ที่ส่งค่ากลับไปด้วย หากเรานำ business logic เหล่านี้เขียนไว้ใน Resource ตรง ๆ ก็อาจจะส่งผลเสียให้ business logic เหล่านี้ไม่สามารถ reuse ได้ และอาจเกิด duplicate code ในกรณีที่มีการส่งค่าลักษณะคล้ายกันซ้ำ ๆ

ในกรณีนี้เราจะใช้ Layer ของ Presenter / Transformer มาช่วยในการแปลงค่าบางอย่างของ model หรือ collection ก่อนที่จะส่งค่ากลับ เช่น

class UserPresenter {
    public function transform(User $user): array {
        return [
            'id' => $user->id,
            'full_name' => "{$user->first_name} {$user->last_name}",
            'status' => $user->is_active ? 'active' : 'inactive',
        ];
    }
}

class UserResource extends JsonResource {
    public function toArray($request) {
        return (new UserPresenter())->transform($this->resource);
    }
}
php

จากตัวอย่างจะเห็นว่าเราสามารถแยก business logic บางอย่างออกมาจาก Resource ได้ และยังสามารถนำ logic เหล่านี้ไป reuse ใช้กับส่วนอื่น ๆ ในโปรเจกต์ได้อีกด้วย

🧩 Contextual Resource เปลี่ยน Resource ไปตาม context#

บางครั้งเราอาจต้องการ API ที่มีลักษณะคล้ายกันหรือดึงข้อมูลแบบเดียวกัน แต่อาจมีค่าบางอย่างเปลี่ยนไปตาม context ของระบบที่เรียกใช้ เช่น permission ของ user หรือ module ที่เรียกใช้งาน เป็นต้น การแสดงผลเหล่านี้แม้จะมีความใกล้เคียงกันแต่ก็อาจมีบางส่วนแตกต่างกันตาม context เราจึงสามารถประยุกต์ใช้ API Resource ของเราได้ ดังนี้

class UserResource extends JsonResource {
    protected $context;

    public function __construct($resource, $context = []) {
        parent::__construct($resource);
        $this->context = $context;
    }

    public function toArray($request) {
        $data = [
            'id' => $this->id,
            'name' => $this->name,
        ];

        if ($this->context['role'] === 'admin') {
            $data['email'] = $this->email;
            $data['last_login'] = $this->last_login;
        }

        return $data;
    }
}
php

จะเห็นว่าเมื่อ context เปลี่ยน ค่าบางอย่างของ API Resource จะเปลี่ยนไป แต่ค่าหลัก ๆ ยังคงอยู่เหมือนเดิม ทำให้ผลลัพธ์มีความยืดหยุ่นมากยิ่งขึ้น

📦 Response Envelope Pattern หุ้มทุก Response ด้วยรูปแบบเดียวกัน#

กรณีที่ระบบที่พัฒนามีนักพัฒนาหลายคน และเป็นระบบใหญ่ การที่ทุก API Resource จะมีมาตรฐานเดียวกันเป็นสิ่งที่ดี แต่หากทุกคนต้องมาคอยเขียน response structure ให้เหมือนกัน แม้จะมีเอกสารกลางคอยควบคุมแต่ก็คงเป็นเรื่องยุ่งยากอยู่ดี การมีตัวช่วยห่อหุ้ม response ไว้จะช่วยให้การจัดการง่ายขึ้นอย่างมาก

สมมุติว่าในโปรเจกต์ของเราต้องการ response structure ที่มีโครงสร้างแบบนี้

{
  "status": "success",
  "data": {...},
  "meta": {
    "request_id": "xxx",
    "timestamp": 123456
  }
}
json

สิ่งที่เราต้องการคือ BaseResource ที่ช่วยห่อหุ้มโครงสร้างดังกล่าวและส่งข้อมูลเพียงแค่ data ที่ต้องการ ดังนี้

class BaseResource {
    public static function success($data, $meta = []) {
        return response()->json([
            'status' => 'success',
            'data' => $data,
            'meta' => array_merge($meta, [
                'request_id' => Str::uuid(),
                'timestamp' => now()->timestamp,
            ]),
        ]);
    }
}
php

จากนั้นเมื่อเรียกใช้งาน BaseResource ที่ตั้งค่าไว้ก็จะทำให้ response ของเรามีโครงสร้างพื้นฐานตามที่กำหนด

📝 Polymorphic Resource เมื่อ Resource เปลี่ยนตาม Model#

แม้ Resource ของ Laravel โดยปกติจะแยกตาม Model อยู่แล้ว แต่เราก็สามารถออกแบบโครงสร้างของ Resource ใหม่ให้สามารถใช้ Resource ร่วมกัน แต่แบ่งหน้าที่การจัดการ format ของ Model ไปที่ Presenter ได้ เช่น

class ContentResource extends JsonResource {
    public function toArray($request) {
        return match (get_class($this->resource)) {
            Post::class => (new PostPresenter())->transform($this->resource),
            Video::class => (new VideoPresenter())->transform($this->resource),
            Podcast::class => (new PodcastPresenter())->transform($this->resource),
        };
    }
}
php

จากตัวอย่างจะเห็นว่า ทั้ง Post, Video และ Podcast เป็น Resource ที่อยู่ในกลุ่มเดียวกัน และมักจะมี logic ในการ response ที่คล้ายกัน แต่ก็อาจจะมีบาง attributes ที่ต้องการรายละเอียดต่างกัน ในจุดนี้เราสามารถประยุกต์ใช้ Presenter เข้ามาช่วยได้ขึ้นอยู่กับสถานการณ์

🚀 Caching Layer ให้ response ได้เร็วขึ้น#

บางครั้ง API ที่เรียกไม่ได้เปลี่ยนแปลงข้อมูลบ่อย การใช้ cache เข้ามาช่วยเป็นเทคนิคพื้นฐานที่ช่วยให้ Laravel สามารถรองรับ traffic ที่สูงขึ้นได้ และในกรณีนี้เราสามารถนำ cache มาใช้ได้ตั้งแต่ Resource Layer เลย

class CachedResource extends JsonResource {
    public function toArray($request) {
        return Cache::remember("resource:{$this->id}", 60, function() {
            return parent::toArray($request);
        });
    }
}
php

เพียงเท่านี้ API ของเราก็สามารถรองรับ traffic ที่มากขึ้นได้แล้ว

🛠️ Repository Pattern Integration จัดการ Model อย่างมีประสิทธิภาพ#

แม้ตัวของ Resource เองจะจัดการ Model relations ได้อยู่แล้ว แต่เมื่อระบบใหญ่ขึ้น เรามักจะใช้ Repository Pattern เข้ามาช่วยจัดการโครงสร้างของ Model อยู่แล้ว

เราจึงสามารถนำ Repository Pattern นี้มาต่อยอดใช้กับ API Resource ได้เลยโดยที่ไม่ต้องให้ Resource จัดการ Model relations เอง

$users = $this->userRepository->getWithRelations();
return UserResource::collection($users);
php

ด้วย Pattern นี้จะทำให้เราสามารถนำ Repository Pattern มา reuse ใช้ได้อย่างมีประสิทธิภาพมากยิ่งขึ้น

🎯 บทสรุป#

แม้ Laravel Resource จะเป็นเครื่องมือที่ทรงพลังในตัวเองอยู่แล้ว แต่จะเห็นได้ว่าเรายังสามารถประยุกต์และแก้ไขเพิ่มเติมบางอย่าง เพื่อให้การพัฒนาสามารถทำได้ง่ายและยืดหยุ่นมากยิ่งขึ้น อีกทั้งยังช่วยเพิ่ม performance ให้แก่ระบบอีกด้วย

ซึ่งสิ่งที่นำมาประยุกต์ใช้นั้น ก็ล้วนแล้วแต่เป็นพื้นฐานในการเขียน Laravel ทั้งสิ้น ตัวแอดมินเองหวังว่าบทความนี้จะช่วยให้ผู้อ่านเห็นประโยชน์ของ การออกแบบโค้ดในเชิงพื้นฐานและการประยุกต์ใช้เพื่อต่อยอดให้เกิดประโยชน์สูงที่สุด ☕

ขอให้มีความสุขกับการเขียนโค้ด 🥰

Code, coffee, and calm — the holy trinity of a good day. ☕

Laravel API Resource Patterns - ยกระดับการจัดการ Response ให้ทรงพลัง
Author Coffee Stack
Published at September 1, 2025