Fragment และ Alias
บทเรียนสุดท้ายของโมดูลนี้ว่าด้วยเครื่องมือสามอย่างที่ทำให้ query สะอาดขึ้น ไม่ใช่ทรงพลังขึ้น Fragment ให้ตั้งชื่อ selection set แล้วนำกลับมาใช้ซ้ำ Inline fragment ให้ selection แตกแขนงตาม type ส่วน Alias ให้เปลี่ยนชื่อ field ใน response ทั้งสามอย่างไม่เปลี่ยนสิ่งที่ server ทำเลย เปลี่ยนแค่ว่า query ของคุณอ่านง่ายและยืดหยุ่นแค่ไหน
Fragment
หัวข้อที่มีชื่อว่า “Fragment”พอ field ชุดเดียวกันโผล่หลายที่ การก็อปไปวางทุกจุดคือกับดักตอน maintain ตัว fragment คือ selection set ที่มีชื่อ นิยามครั้งเดียวแล้ว spread ไปใช้ตรงไหนก็ได้ ประกาศด้วย keyword fragment และระบุ type ที่ใช้ได้ด้วย on
fragment TrackFields on Track { id title durationSeconds}จากนั้น spread เข้าไปใน selection set ด้วย operator ... ผลลัพธ์เหมือนเขียน field ชุดนั้นไว้ตรงนั้นเลย
{ track(id: "t1") { ...TrackFields } featured: track(id: "t2") { ...TrackFields }}selection ทั้งสองชุดดึง id, title และ durationSeconds เข้ามาโดยไม่ต้องเขียนซ้ำ แก้ fragment ที่เดียว ทุกจุดที่ spread ก็อัปเดตตามหมด ได้ผลตอบแทนแบบเดียวกับการแยก code ที่ซ้ำกันออกมาเป็น function
Inline fragment
หัวข้อที่มีชื่อว่า “Inline fragment”บางที field ก็คืน type ที่เป็นได้หลาย object type คือ interface หรือ union นั่นเอง เวลาจะเลือก field ที่มีอยู่เฉพาะบน type ใด type หนึ่ง ให้ใช้ inline fragment เขียนเป็น operator ... ตามด้วย on SomeType แล้วต่อด้วย selection set โดยไม่ต้องตั้งชื่อ
{ searchResult { ... on Track { title } ... on Artist { name } }}กรณีนี้ searchResult จะ resolve เป็น Track หรือ Artist ก็ได้ ตัว inline fragment จึงบอกว่า “ถ้าเป็น Track ขอ title ถ้าเป็น Artist ขอ name” แล้วมีเฉพาะแขนงที่ตรง type เท่านั้นที่โผล่ใน response นี่คือวิธีแตกแขนงตาม type ภายใน selection เดียว
flowchart TD
Frag["fragment TrackFields on Track { id, title, durationSeconds }"]
Frag -->|"... spread"| S1["hit: track(id: t1)"]
Frag -->|"... spread"| S2["deepCut: track(id: t2)"]
S1 --> R["Response with two aliased keys"]
S2 --> R ปกติ field จะโผล่ใน response ด้วยชื่อของตัวเอง ส่วน alias ให้คุณเลือก key อื่นได้ เขียนเป็น aliasName: fieldName นำหน้า field ตัวนี้จำเป็นตอนที่เลือก field เดียวกันสองครั้งด้วย argument คนละชุด เพราะถ้าไม่มี alias ผลลัพธ์สองอันจะชนกันที่ key เดียวกัน
{ first: track(id: "t1") { title } second: track(id: "t2") { title }}response จะมีสอง key แยกกันคือ first และ second แต่ละตัวเก็บ track ของตัวเอง alias เป็นเรื่องของ รูปร่าง response ล้วน ๆ ไม่แตะ schema หรือ resolver เลยสักนิด และยังสะดวกเวลาต้องดัดชื่อ field ให้ตรงกับที่ client code รออยู่
Fragment และ alias ทำงานร่วมกัน
หัวข้อที่มีชื่อว่า “Fragment และ alias ทำงานร่วมกัน”ตัวอย่างด้านล่างนิยาม fragment ชื่อ TrackFields แล้ว spread เข้าไปใน selection ของ field track สองชุด พร้อมใช้ alias hit กับ deepCut ให้ผลลัพธ์แยกคนละ key กด Run แล้วดู key ของ response
response มี key ระดับบนสุดสองตัวคือ hit และ deepCut แทนที่จะเป็น track ตัวเดียวที่ชนกัน นั่นคือผลงานของ alias และแต่ละตัวก็เก็บ field ครบชุดจาก TrackFields ที่เขียนครั้งเดียวแล้วใช้ซ้ำสองรอบ นั่นคือผลงานของ fragment สองอย่างรวมกันทำให้ query สั้นลงและ response มีรูปร่างที่ใช้งานง่าย
| ข้อดี | ข้อแลกเปลี่ยน |
|---|---|
| Fragment ลด duplication ของ field selection ข้าม query | fragment มากเกินทำให้ query อ่านยาก |
| Alias ทำให้ query field เดียวกันสองครั้งด้วยชื่อต่างกัน | Fragment ที่ไม่ใช้สร้าง dead code ใน client |
| Fragment ช่วยให้ component-driven query (Relay) | Alias ที่ไม่สื่อความหมายทำให้ response งงยิ่งขึ้น |
| Inline fragment ช่วย handle Union และ Interface type | Fragment spread ลึกมากทำให้ query ขนาดใหญ่ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”Copy-paste Field แทนใช้ Fragment อาการ:
- query 5 ชิ้นมี field ชุดเดียวกัน (
id,name,avatar) เขียนซ้ำทุกที่ - เปลี่ยน field เดียวต้องแก้ 5 query
- สร้าง fragment
UserBasicInfoแล้ว spread ใน query ทั้งหมด
Alias ที่ไม่สื่อความหมาย อาการ:
data1: user(id: 1) { name }และdata2: user(id: 2) { name }- response มี
data1และdata2ที่ client ต้องรู้ว่าหมายถึงอะไร - ใช้ alias ที่สื่อ intent:
primaryUser: user(id: $id1),secondaryUser: user(id: $id2)
💡 ตัวอย่างจากของจริง
Relay (Meta/Facebook):
- บังคับ pattern “colocation” — component ประกาศ fragment ของตัวเองที่ต้องการ
- query ระดับ page รวม fragment จาก component ทั้งหมดอัตโนมัติ
Apollo Client:
useFragmenthook ทำให้ component subscribe เฉพาะ field ที่ตัวเองประกาศใน fragment