GraphQL — คือภาษาแบบสอบถามสำหรับ API และสภาพแวดล้อมรันไทม์สำหรับดำเนินการสอบถามเหล่านี้ พัฒนาโดย Facebook ในปี 2012 และเปิดตัวในปี 2015 ต่างจาก REST ที่เซิร์ฟเวอร์กำหนดโครงสร้างการตอบสนอง GraphQL อนุญาตให้ไคลเอนต์ระบุได้อย่างแม่นยำว่าต้องการข้อมูลใด ขจัดปัญหา overfetching และ underfetching อย่างสมบูรณ์ จากข้อมูลของ State of JavaScript Survey (2025) นักพัฒนาที่ตอบแบบสำรวจ 35% ใช้ GraphQL และในหมู่บริษัทขนาดใหญ่ GitHub, Shopify, Airbnb และ The New York Times ได้นำไปใช้ GraphQL รองรับการดำเนินการสามประเภท: query (การอ่าน), mutation (การเขียน) และ subscription (การอัปเดตแบบ real-time ผ่าน WebSocket)
สาระสำคัญ
GraphQL — คือข้อกำหนดและสภาพแวดล้อมรันไทม์สำหรับ API ที่ให้ไคลเอนต์ควบคุมข้อมูลที่ได้รับได้อย่างสมบูรณ์ พัฒนาโดยวิศวกรของ Facebook เพื่อแก้ปัญหาของแอปพลิเคชันมือถือ News Feed ข้อกำหนดดังกล่าวได้รับการเผยแพร่เป็นมาตรฐานเปิดในปี 2015 ตั้งแต่ปี 2018 GraphQL อยู่ภายใต้การดูแลของ GraphQL Foundation โดยได้รับการสนับสนุนจาก Linux Foundation และบริษัทต่างๆ เช่น Apollo, AWS, GitHub, SAP และอื่นๆ
ต่างจาก REST ที่แต่ละ endpoint ส่งคืนโครงสร้างข้อมูลที่ตายตัว GraphQL ใช้ endpoint เดียวที่รับสตริงคำสั่งสอบถาม ไคลเอนต์อธิบายในคำสั่งสอบถามว่าต้องการฟิลด์ใด และเซิร์ฟเวอร์จะส่งคืนเฉพาะฟิลด์เหล่านั้น ตัวอย่างเช่น คำสั่งสอบถาม { user(id: "1") { name email } } จะส่งคืนเฉพาะ name และ email ของผู้ใช้ โดยไม่มีฟิลด์เกินจำเป็นอย่าง address, phone หรือ createdAt ที่ต้องได้รับใน REST
GraphQL ไม่ผูกติดกับฐานข้อมูลหรือภาษาใดภาษาหนึ่งโดยเฉพาะ ข้อกำหนดกำหนดเพียงรูปแบบของคำสั่งสอบถามและการตอบสนองเท่านั้น มีการใช้งานเซิร์ฟเวอร์บน Node.js (graphql-js, Apollo Server), Kotlin (graphql-kotlin, Netflix DGS Framework), Python (Graphene, Strawberry), Ruby (graphql-ruby) และภาษาอื่นๆ ไลบรารีไคลเอนต์พร้อมใช้งานสำหรับแพลตฟอร์มหลักทั้งหมด รวมถึง Apollo Client สำหรับ iOS, Android และเว็บ
สถาปัตยกรรม GraphQL ประกอบด้วยองค์ประกอบหลักสามส่วน: สคีมา (Schema), รีโซลเวอร์ (Resolvers) และเอนจินการทำงาน (GraphQL Engine) สคีมากำหนดว่าชนิดข้อมูลใดบ้างที่พร้อมใช้งาน สามารถดำเนินการสอบถามใดได้บ้าง และรับอาร์กิวเมนต์ใดบ้าง รีโซลเวอร์คือฟังก์ชันบนเซิร์ฟเวอร์ที่ส่งคืนข้อมูลสำหรับแต่ละฟิลด์ของสคีมา เอนจินการทำงานรับคำสั่งสอบถามขาเข้า ตรวจสอบความถูกต้องตามสคีมา เรียกรีโซลเวอร์ที่เกี่ยวข้อง และรวบรวมการตอบสนอง
ขั้นตอนการประมวลผลคำสั่งสอบถามเป็นดังนี้:
ข้อได้เปรียบสำคัญของสถาปัตยกรรม GraphQL — การแก้ปัญหาในระดับฟิลด์ ใน REST นักพัฒนาจะได้รับฟิลด์ทั้งหมดของทรัพยากร (อาจมีฟิลด์เกินจำเป็น) หรือใช้ส่วนขยายอย่าง ?fields=name,email ใน GraphQL การกรองนี้ถูกbuilt-in ในภาษา: แต่ละคำสั่งสอบถามระบุอย่างชัดเจนว่าต้องการฟิลด์ใด และเซิร์ฟเวอร์ส่งคืนเฉพาะฟิลด์เหล่านั้น สิ่งนี้สำคัญโดยเฉพาะสำหรับแอปพลิเคชันมือถือ ซึ่งปริมาณข้อมูลที่ส่งมีผลโดยตรงต่อความเร็วในการโหลดและการใช้ข้อมูล
GraphQL กำหนดการดำเนินการสามประเภท ซึ่งแต่ละประเภทสอดคล้องกับสถานการณ์การโต้ตอบที่เฉพาะเจาะจง Query — สำหรับการอ่านข้อมูล คล้ายกับ GET ใน REST Mutation — สำหรับการเปลี่ยนแปลงข้อมูล (สร้าง, อัปเดต, ลบ) คล้ายกับ POST/PUT/DELETE Subscription — สำหรับการอัปเดตแบบ real-time ผ่าน WebSocket ซึ่งไม่มีความคล้ายคลึงโดยตรงใน REST แบบคลาสสิก (ต้องใช้โซลูชันเพิ่มเติมอย่าง WebSocket หรือ Server-Sent Events)
ไวยากรณ์พื้นฐานของคำสั่งสอบถามนั้นเข้าใจได้โดยสัญชาตญาณ:
// Simple query with argument
query {
user(id: "42") {
name
email
avatarUrl
}
}
// Mutation returning changed data
mutation {
updateProfile(name: "John") {
id
name
updatedAt
}
}
// Subscription — listens to real-time updates
subscription {
newMessage(chatId: "chat_1") {
id
text
sender { name }
}
}
Query ถูกดำเนินการแบบขนาน — ฟิลด์ทั้งหมดในระดับเดียวกันจะถูกโหลดพร้อมกัน ซึ่งช่วยให้โหลดข้อมูลที่เกี่ยวข้อง (ผู้ใช้และโพสต์ของเขา) ด้วยคำสั่งสอบถามเดียวโดยไม่ต้องมี round-trip หลายครั้ง Mutation ถูกดำเนินการแบบตามลำดับ — มิวเทชันในคำสั่งสอบถามเดียวจะดำเนินการทีละรายการตามลำดับที่ประกาศ Subscription สร้างการเชื่อมต่อถาวรผ่าน WebSocket ซึ่งเซิร์ฟเวอร์ส่งข้อมูลเมื่อเกิดเหตุการณ์
การดำเนินการสามารถรับ ตัวแปร เพื่อแยกข้อมูลออกจากคำสั่งสอบถาม ไดเรกทีฟ (@include, @skip) สำหรับการรวมฟิลด์แบบมีเงื่อนไข และ แฟรกเมนต์ สำหรับการใช้ชุดฟิลด์ซ้ำ ความสามารถเหล่านี้ทำให้คำสั่ง GraphQL มีความยืดหยุ่นและนำกลับมาใช้ใหม่ได้ ซึ่งสำคัญโดยเฉพาะในโปรเจกต์ขนาดใหญ่ที่มีหน้าจอและคอมโพเนนต์จำนวนมาก
พื้นฐานของ GraphQL คือ ระบบชนิด ที่อธิบายข้อมูลและการดำเนินการทั้งหมดที่เป็นไปได้ของ API สคีมา (Schema) คือคำอธิบายชนิดที่เซิร์ฟเวอร์สามารถส่งคืนได้และคำสั่งสอบถามที่รับได้ สคีมาเขียนด้วยภาษา Schema Definition Language (SDL) และทำหน้าที่เป็นสัญญาระหว่างไคลเอนต์และเซิร์ฟเวอร์ ไคลเอนต์สามารถรับสคีมาผ่านการตรวจสอบภายใน (introspection) — คำสั่งสอบถามพิเศษ __schema ที่ส่งคืนคำอธิบายแบบเต็มของ API
ตัวอย่างสคีมาสำหรับบล็อก:
// SDL — Schema Definition Language
type User {
id: ID!
name: String!
email: String
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
type Query {
user(id: ID!): User
posts(page: Int): [Post!]!
}
เครื่องหมายอัศเจรีย์ (!) หมายถึงฟิลด์ non-null — ฟิลด์นี้จะปรากฏในการตอบสนองอย่างแน่นอน วงเล็บเหลี่ยม [ ] หมายถึงรายการ GraphQL รองรับชนิดสเกลาร์ (Int, Float, String, Boolean, ID), ชนิดออบเจ็กต์, enum, union, interface และชนิด input (สำหรับอาร์กิวเมนต์ของมิวเทชัน) การกำหนดชนิดที่เข้มงวดทำให้ API มีการจัดทำเอกสารในตัวและช่วยให้เครื่องมือไคลเอนต์สร้างโค้ดได้: ชนิด TypeScript, คลาสข้อมูล Kotlin, โครงสร้าง Swift
การตรวจสอบภายใน (Introspection) — ความสามารถเฉพาะของ GraphQL ที่ไม่มีใน REST ไคลเอนต์สามารถส่งคำสั่งสอบถามไปยังสคีมาและรับคำอธิบายแบบเต็มของชนิด ฟิลด์ อาร์กิวเมนต์ และไดเรกทีฟทั้งหมด นี่คือพื้นฐานของเครื่องมืออย่าง GraphiQL และ Apollo Studio ที่สร้างเอกสารและการเติมอัตโนมัติสำหรับนักพัฒนาโดยอัตโนมัติ การตรวจสอบภายในยังช่วยให้เขียนการทดสอบอัตโนมัติที่ตรวจสอบความสอดคล้องของสคีมากับโครงสร้างที่คาดหวังได้
การเลือกระหว่าง GraphQL และ REST เป็นหนึ่งในคำถามทางสถาปัตยกรรมที่สำคัญเมื่อออกแบบ API ทั้งสองวิธีมีจุดแข็งและจุดอ่อนของตัวเอง และการเลือกขึ้นอยู่กับความต้องการเฉพาะของโปรเจกต์ REST ดีกว่าในเรื่องความเรียบง่ายและความเป็นสากล GraphQL ดีกว่าในเรื่องความยืดหยุ่นและประสิทธิภาพของคำสั่งสอบถาม มาดูตารางเปรียบเทียบกัน
| เกณฑ์ | REST | GraphQL |
|---|---|---|
| โครงสร้างการตอบสนอง | ตายตัว ฝั่งเซิร์ฟเวอร์ | ยืดหยุ่น ฝั่งไคลเอนต์ |
| Overfetching | บ่อยครั้ง — เซิร์ฟเวอร์ส่งคืนทุกฟิลด์ | ไม่มี — ไคลเอนต์ขอเฉพาะที่ต้องการ |
| จำนวนคำขอ | หลาย round-trips | หนึ่งคำขอสำหรับข้อมูลทั้งหมด |
| การแคช | HTTP แคชแบบเนทีฟ | ต้องกำหนดค่าด้วยตนเอง |
| การกำหนดชนิด | ไม่ได้ built-in (ขึ้นอยู่กับรูปแบบ) | เข้มงวด ผ่าน SDL สคีมา |
| เครื่องมือ | curl, Postman, Swagger | GraphiQL, Apollo Studio, Introspection |
| การอัปโหลดไฟล์ | แบบเนทีฟผ่าน multipart | ต้องใช้โปรโตคอลเพิ่มเติม |
| ประสิทธิภาพ | คาดการณ์ได้ ปรับให้เหมาะสมง่ายกว่า | ขึ้นอยู่กับความซับซ้อนของคำสั่งสอบถามที่ซ้อนกัน |
ข้อเสียหลักของ GraphQL — ความซับซ้อนในการแคช ใน REST การแคช HTTP ทำงานในระดับ URL: หนึ่งคำขอไปยัง /api/users/42 ส่งคืนโครงสร้างที่เหมือนกันเสมอ และสามารถแคชการตอบสนองตาม URL ได้ ใน GraphQL คำขอทั้งหมดไปยัง endpoint เดียว โครงสร้างการตอบสนองขึ้นอยู่กับเนื้อหาของคำขอ เพื่อแก้ปัญหานี้ Apollo Client ใช้แคชที่ทำให้เป็นมาตรฐาน (normalized cache) ฝั่งไคลเอนต์ ซึ่งแบ่งการตอบสนองเป็นเอนทิตีแยกตาม id และอัปเดตโดยอัตโนมัติเมื่อได้รับข้อมูลใหม่
อีกประเด็นสำคัญ — ปัญหา N+1 เมื่อขอข้อมูลที่ซ้อนกัน (เช่น โพสต์ของผู้ใช้และความคิดเห็นในแต่ละโพสต์) GraphQL อาจดำเนินการ SQL query แยกต่างหากสำหรับแต่ละรายการในรายการ แก้ไขได้ด้วย DataLoader — ยูทิลิตี้สำหรับการจัดกลุ่มและแคชคำสั่งสอบถามฐานข้อมูล ซึ่งจัดกลุ่มคำสั่งสอบถามแต่ละรายการเป็นชุดเดียว ใน REST ปัญหานี้เด่นชัดน้อยกว่าเนื่องจากนักพัฒนาควบคุมโครงสร้างการตอบสนองบนเซิร์ฟเวอร์
มาดูตัวอย่างการใช้งาน GraphQL ในแอปพลิเคชันมือถือบน Kotlin กับ Apollo Client ตัวอย่างแสดงสถานการณ์ทั่วไป: การโหลดข้อมูลสำหรับหน้าจอโปรไฟล์ (query), การสร้างโพสต์ใหม่ (mutation) และการสมัครรับความคิดเห็นใหม่ (subscription) แต่ละตัวอย่างรวมทั้งคำสั่ง GraphQL และโค้ดฝั่งไคลเอนต์
หนึ่งคำสั่ง GraphQL โหลดผู้ใช้ โพสต์ล่าสุดของเขา และจำนวนผู้ติดตามทั้งหมด ใน REST ต้องใช้อย่างน้อย 2-3 คำขอ: /users/42, /users/42/posts, /users/42/stats GraphQL รวมเป็นหนึ่ง round-trip ลดเวลาโหลดหน้าจอบนการเชื่อมต่อที่ช้า
// GraphQL query (in .graphql file)
query ProfileScreen($userId: ID!) {
user(id: $userId) {
name
bio
avatarUrl
posts(limit: 10) {
id
title
createdAt
}
followersCount
followingCount
}
}
// Client call (Apollo Client + Kotlin)
val response = apolloClient
.query(ProfileScreenQuery(userId = "42"))
.execute()
binding.nameText.text = response.data?.user?.name
มิวเทชันไม่เพียงสร้างทรัพยากร แต่ยังส่งคืนข้อมูลล่าสุดสำหรับอัปเดต UI ฟิลด์ __typename ถูกใช้โดย Apollo Client สำหรับการทำให้แคชเป็นมาตรฐาน — ไคลเอนต์จะอัปเดตระเบียน Post ในแคชโดยอัตโนมัติเมื่อได้รับการตอบสนองของมิวเทชันที่สำเร็จ
// GraphQL mutation
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
createdAt
author {
id
name
}
}
}
// Mutation call with input type
val input = CreatePostInput(
title = "New post about GraphQL",
content = "GraphQL simplifies working with API..."
)
val result = apolloClient
.mutation(CreatePostMutation(input))
.execute()
ข้อได้เปรียบสำคัญของ GraphQL เหนือ REST ในบริบทของการพัฒนาแอปมือถือ — การสร้างโค้ดอัตโนมัติ Apollo Client สำหรับ Kotlin (Apollo GraphQL) สร้างคลาสที่ปลอดภัยด้านชนิดจากไฟล์ .graphql ในขั้นตอนการ build หากเซิร์ฟเวอร์เปลี่ยนสคีมา โปรเจกต์จะไม่ build จนกว่าจะอัปเดตคำสั่งสอบถาม สิ่งนี้ป้องกันข้อผิดพลาด runtime ที่พบได้ทั่วไปใน REST ซึ่งการเปลี่ยนแปลงโครงสร้างการตอบสนองอาจไม่มีใครสังเกตเห็นระหว่างการพัฒนา
ระบบนิเวศของ GraphQL ประกอบด้วยไลบรารีและเครื่องมือสำคัญหลายอย่างที่ทำให้การพัฒนาและการใช้งานง่ายขึ้น Apollo Client — ไลบรารีไคลเอนต์ที่ได้รับความนิยมมากที่สุด รองรับ React, iOS, Android และ Kotlin Multiplatform Relay จาก Facebook — ทางเลือกสำหรับแอปพลิเคชัน React ที่มีแนวทางการจัดการข้อมูลและการแคชที่ไม่เหมือนใคร การเลือกระหว่าง Apollo และ Relay ขึ้นอยู่กับแพลตฟอร์มและข้อกำหนดด้านประสิทธิภาพ
ฝั่งเซิร์ฟเวอร์ Apollo Server (Node.js), Netflix DGS Framework (Kotlin/Java) และ graphql-ruby เป็นผู้นำ สำหรับการพัฒนาสคีมาและการทดสอบคำสั่งสอบถาม ใช้ GraphiQL — IDE แบบโต้ตอบที่built-in ในเบราว์เซอร์ Apollo Studio ให้เมตริกประสิทธิภาพ การติดตามคำสั่งสอบถาม และการจัดการสคีมาสำหรับสภาพแวดล้อม production นอกจากนี้ยังมี GraphQL Code Generator — เครื่องมือที่สร้างชนิด TypeScript, Kotlin, Swift และ Dart จาก SDL สคีมา
สำหรับการพัฒนาแอปมือถือ Apollo Kotlin (Apollo GraphQL) น่าสนใจเป็นพิเศษ — ไลบรารีที่เขียนด้วย Kotlin อย่างสมบูรณ์ รองรับ coroutines, Flow และ Multiplatform ช่วยให้ใช้คำสั่ง GraphQL ร่วมกันสำหรับ Android และ iOS ในโปรเจกต์ Kotlin Multiplatform Apollo Kotlin ทำให้แคชเป็นมาตรฐาน รองรับข้อผิดพลาดในระดับฟิลด์ (partial errors) และสร้างโมเดลข้อมูลจากไฟล์ .graphql โดยอัตโนมัติ สิ่งนี้ทำให้ GraphQL เป็นตัวเลือกที่ดีกว่าสำหรับโปรเจกต์มือถือขนาดใหญ่ที่ความเร็วในการพัฒนาและความปลอดภัยด้านชนิดมีความสำคัญ
คำถามที่พบบ่อย
GraphQL ไม่ได้แทนที่ REST แต่เสนอแนวทางทางเลือก REST เหมาะกว่าสำหรับ CRUD-API ง่ายๆ การแคชผ่าน HTTP และ API สาธารณะที่มีโหลดคาดการณ์ได้ GraphQL เหมาะสมที่สุดสำหรับอินเทอร์เฟซที่ซับซ้อนซึ่งมีข้อมูลที่เกี่ยวข้องจำนวนมาก
การย้ายสามารถทำได้ ทีละน้อย: GraphQL สามารถทำงานเป็นชั้น (gateway) หน้า REST services ที่มีอยู่ บริษัทหลายแห่งเพิ่ม GraphQL ควบคู่ไปกับ REST โดยไม่ปิด API เดิม การเปลี่ยนทั้งหมดต้องเขียนรีโซลเวอร์ใหม่
N+1 เกิดขึ้นเมื่อดำเนินการ query ฐานข้อมูลแยกต่างหากสำหรับแต่ละรายการในรายการ แก้ไขด้วย DataLoader — ไลบรารีที่รวม query แต่ละรายการเป็นชุดเดียวและแคชผลลัพธ์ภายในหนึ่ง HTTP request
ข้อกำหนด GraphQL ไม่ได้กำหนดการอัปโหลดไฟล์โดยตรง ในทางปฏิบัติใช้: base64 encoding (ง่ายแต่ไม่มีประสิทธิภาพสำหรับไฟล์ใหญ่), multipart requests ตามโปรโตคอล graphql-multipart-request-spec หรือ REST endpoint แยกต่างหากสำหรับไฟล์
ความปลอดภัยของ GraphQL ต้องมีมาตรการเพิ่มเติม: การจำกัดความลึกของการซ้อน, การจำกัดความซับซ้อนของคำสั่งสอบถาม, rate limiting ในระดับการดำเนินการ การตรวจสอบภายในสคีมาแบบสาธารณะอาจเปิดเผยโครงสร้างข้อมูล — ใน production ควรปิดการใช้งาน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม