GraphQL vs REST
REST รับใช้เว็บมาดีตลอดสองทศวรรษ และทีมส่วนใหญ่ที่หันมาใช้ GraphQL ก็ย้ายมาจาก REST คำถามที่ตรงประเด็นจึงไม่ใช่ “อันไหนดีกว่า” แต่เป็น “แต่ละอันออกแบบมาเพื่ออะไร และเรากำลังแลกอะไรอยู่” บทนี้จะวางทั้งสองเทียบกันแบบเคียงข้าง
หลาย endpoint เทียบกับ graph เดียว
หัวข้อที่มีชื่อว่า “หลาย endpoint เทียบกับ graph เดียว”REST API จำลอง resource เป็น URL หากต้องการสร้างหน้าโปรไฟล์ คุณอาจต้องเรียกถึงสามตัว:
GET /users/42GET /users/42/postsGET /posts/99/commentsrequest ของ GraphQL ที่เทียบเท่าคือ query เดียวไปยัง endpoint เดียว เดินจาก user ไปยัง posts ของพวกเขา ไปยัง comments ของแต่ละ post ใน round trip เดียว:
{ user(id: "42") { name posts { title comments { body } } }}flowchart TB
subgraph REST["REST — three round trips"]
direction LR
R1["GET /users/42"] --> R2["GET /users/42/posts"] --> R3["GET /posts/99/comments"]
end
subgraph GQL["GraphQL — one round trip"]
direction LR
G1["POST /graphql"] --> G2["user -> posts -> comments"]
end การ over- และ under-fetching
หัวข้อที่มีชื่อว่า “การ over- และ under-fetching”นี่คือจุดที่สัมผัสได้ถึงความแตกต่างในแต่ละวัน
- กับ REST นั้น
GET /users/42คืน payload คงที่ หากคุณต้องการแค่ name คุณก็ยังได้รับ record ทั้งหมดอยู่ดี (over-fetching) หากคุณต้องการ posts ที่เกี่ยวข้องคุณก็ต้องเรียกอีกครั้ง (under-fetching) - กับ GraphQL คุณระบุ field ที่ต้องการได้แม่นยำ ครอบคลุม type ที่เกี่ยวข้อง แล้วได้ทั้งหมดกลับมาใน response เดียว ปัญหาทั้งสองข้อจึงไม่เกิดตั้งแต่แรก
การเปรียบเทียบแบบเคียงข้าง
หัวข้อที่มีชื่อว่า “การเปรียบเทียบแบบเคียงข้าง”| ประเด็น | REST | GraphQL |
|---|---|---|
| Endpoint | หลายตัว หนึ่งตัวต่อหนึ่ง resource | endpoint graph เดียว |
| รูปร่าง response | กำหนดโดย server | เลือกโดย client |
| Over/under-fetching | เกิดบ่อย | เลี่ยงได้ตั้งแต่การออกแบบ |
| Versioning | มักใช้ URL อย่าง /v1, /v2 | วิวัฒน์ schema; deprecate field |
| HTTP caching | ง่าย — URL cache ได้ดี | ยากกว่า — ต้องใช้ caching ระดับแอปหรือ persisted-query |
| ความค้นพบได้ | OpenAPI/เอกสาร ตามธรรมเนียม | introspection ที่มีในตัว schema |
| ความชันในการเรียนรู้ | คุ้นเคยสำหรับทีมส่วนใหญ่ | ต้องเรียน schema, resolver และ N+1 |
Versioning
หัวข้อที่มีชื่อว่า “Versioning”REST API มักทำ version ผ่าน URL — /v1/users แล้วก็ /v2/users ส่วน GraphQL ใช้ การวิวัฒน์อย่างต่อเนื่อง แทน คือเพิ่ม field ใหม่ได้อิสระ (เป็น opt-in อยู่แล้ว client เก่าจึงไม่กระทบ) และ mark field เก่าด้วย @deprecated เพื่อค่อย ๆ พา client ออกจาก field นั้น แทบไม่ต้องกระโดดเวอร์ชันแบบหักดิบเลย
ข้อแลกเปลี่ยนเรื่อง caching
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยนเรื่อง caching”นี่คือต้นทุนที่จริงที่สุดของ GraphQL GET /posts/99 ของ REST คือ URL ที่นิ่ง browser CDN และ proxy จึง cache ให้ฟรี ส่วน query ของ GraphQL มักมาในรูป POST ที่มี query อยู่ใน body ชั้น HTTP caching จึงใช้ไม่ได้ทันทีตามค่าเริ่มต้น ทีมต่าง ๆ ทวงคืนด้วยเทคนิคอย่าง persisted query (ส่ง hash ที่นิ่งแทนข้อความ query เต็ม) และ normalized client cache (แบบที่ Apollo Client หรือ urql มีให้) แก้ได้อยู่ แต่ไม่ฟรี
ดูความแตกต่างของ round trip
หัวข้อที่มีชื่อว่า “ดูความแตกต่างของ round trip”ตัวรันด้านล่างรัน query ของ GraphQL เพียงตัวเดียว ซึ่งในโลกของ REST จะต้องใช้การเรียกแยกกันถึงสามครั้ง สังเกตว่า request เดียวคืนโครงสร้างที่ซ้อนชั้นและพร้อม render
เมื่อไรที่แต่ละอันเหมาะสม
หัวข้อที่มีชื่อว่า “เมื่อไรที่แต่ละอันเหมาะสม”เลือก REST เมื่อ API ของคุณมีรูปร่างแบบ resource และเน้น cache หนัก (นึกถึงเนื้อหาสาธารณะที่อ่านเป็นหลักซึ่งให้บริการผ่าน CDN) เมื่อผู้บริโภคเรียบง่าย หรือเมื่อทีมส่ง REST ได้ดีอยู่แล้วและชิ้นส่วนเพิ่มเติมไม่คุ้มที่จะลงทุน
เลือก GraphQL เมื่อ client หลากหลายต้องการชิ้นส่วนข้อมูลชุดเดียวกันในแบบที่แตกต่างกัน เมื่อมุมมองต่าง ๆ รวบรวม resource ที่เกี่ยวข้องกันหลายตัว เมื่อทีมผลิตภัณฑ์ทำงานเร็วและต้องการเพิ่ม field โดยไม่ต้องประสานงานการปล่อย endpoint หรือเมื่อ strong typing และ introspection ทั่วทั้งพื้นผิวของ API นำมาซึ่งประโยชน์ที่แท้จริง
| REST | GraphQL | |
|---|---|---|
| Endpoint | หลาย endpoint | single /graphql |
| Response | server กำหนด | client เลือก field |
| Versioning | /v1/, /v2/ | schema evolution + deprecation |
| Caching | HTTP cache ง่าย | ต้องใช้ persisted query |
| Type Safety | OpenAPI (optional) | built-in schema |
| Learning Curve | ต่ำ | สูงกว่า |
| ใช้ REST เมื่อ | ใช้ GraphQL เมื่อ |
|---|---|
| public API ที่ต้องการ HTTP cache | หลาย client ต้องการ data shape ต่างกัน |
| simple CRUD ที่ endpoint ชัดเจน | mobile app ที่ bandwidth จำกัด |
| team ไม่มี GraphQL experience | schema ซับซ้อนและมี relationship หลายชั้น |
| file upload heavy | ต้องการ type-safe client code gen |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”ใช้ GraphQL เพราะ hype ไม่ใช่เพราะ problem อาการ:
- API มี 5 endpoint ที่ชัดเจน แต่เปลี่ยนไปใช้ GraphQL เพราะ “modern”
- ทีมเสียเวลา setup GraphQL แทนที่จะ ship feature
คิดว่า GraphQL เร็วกว่า REST เสมอ อาการ:
- ไม่ implement DataLoader — N+1 ทำให้ GraphQL ช้ากว่า REST มาก
- ไม่มี query depth limit — client ส่ง deeply nested query ทำให้ server overload
💡 ตัวอย่างจากของจริง
Twitter:
- ใช้ REST API มาตลอดและ serve ได้ดี — ไม่จำเป็นต้องเปลี่ยน
- พิสูจน์ว่า REST ยังเหมาะสำหรับ high-traffic public API
Airbnb:
- ใช้ GraphQL Federation สำหรับ internal API ระหว่าง team
- แต่ยัง expose REST สำหรับ partner API ที่ต้องการ HTTP caching