Devfavor

Back

GraphQL คืออะไร — ทำไม client ถึงขอข้อมูลเองได้Blur image

เคยเจอไหม — อยากได้แค่ “ชื่อกับรูปโปรไฟล์” ของเพื่อนมาแสดงในหน้าจอ แต่ API ดันส่งข้อมูลกลับมาทั้งก้อน ทั้งวันเกิด ที่อยู่ เบอร์โทร อะไรอีกเยอะแยะที่ไม่ได้ใช้เลย

หรือกลับกัน — หน้าเดียวต้องยิง API สามสี่รอบ รอบแรกขอข้อมูล user รอบสองขอ post รอบสามขอ comment แล้วค่อยเอามาประกอบกันเองที่ฝั่ง frontend กว่าจะครบก็หลายคำขอ

สองอาการนี้มีชื่อเรียกว่า over-fetching (ได้มาเกิน) กับ under-fetching (ได้มาไม่พอ ต้องยิงเพิ่ม) และเป็นปัญหาคลาสสิกของ REST API ที่ทุกคนน่าจะเคยปวดหัวมาบ้าง

GraphQL เกิดมาเพื่อแก้ตรงนี้โดยตรง แนวคิดหลักง่ายมาก — แทนที่ server จะเป็นคนกำหนดว่าจะส่งอะไรกลับ ก็ให้ client เป็นคนบอกเองว่าต้องการ field ไหนบ้าง แล้วได้กลับมาเฉพาะที่ขอ ไม่มีส่วนเกิน


🔍 GraphQL คืออะไรกันแน่#

GraphQL คือ query language (ภาษาสำหรับ query) สำหรับ API พร้อมกับ runtime ฝั่ง server ที่คอยประมวลผล query เหล่านั้นด้วยข้อมูลที่มีอยู่

จุดเด่นที่ทำให้ต่างจาก REST มีอยู่สองข้อ ข้อแรกคือ declarative data fetching — client เขียน query ระบุได้เลยว่าอยากได้ field อะไร แล้ว response ที่กลับมาจะมีหน้าตาตรงตามที่ขอเป๊ะ ขอชื่อกับรูป ก็ได้แค่ชื่อกับรูป

ข้อสองคือทำงานผ่าน single endpoint เดียว เช่น /graphql แทนที่จะมีหลาย endpoint แบบ REST (/users, /users/1/posts, /posts/5/comments …) ทุกคำขอวิ่งเข้าจุดเดียว แล้วเนื้อหาของ query เป็นตัวบอกว่าจะเอาอะไร

อีกอย่างที่เป็นหัวใจคือ GraphQL ทุกตัวถูกนิยามด้วย schema ที่เขียนด้วย Schema Definition Language (SDL) ตัว schema นี้กำหนด types, fields และความสัมพันธ์ของข้อมูลทั้งหมด และเป็น strongly typed หมายความว่าถ้า query ผิด — ขอ field ที่ไม่มีอยู่ หรือใส่ type ผิด — จะรู้ตั้งแต่ก่อนรัน ไม่ต้องรอให้พังตอน runtime

และเพราะ schema นี้ทำตัวเหมือนสัญญา (contract) ระหว่าง frontend กับ backend ตัว API จึง self-documenting ในตัวเอง เปิดดูได้เลยว่ามี type อะไร field ไหนบ้าง ไม่ต้องไปไล่อ่าน doc แยก


🧩 มาจากไหน#

GraphQL เกิดที่ Facebook ราวปี 2012 ตอนทีมกำลัง rebuild แอปมือถือ native โดยเฉพาะส่วน News Feed

ปัญหาที่เจอตอนนั้นคือ developer คิดถึงข้อมูลในหัวเป็น “graph ของ objects” — user มี post, post มี comment, comment มีคนเขียน เชื่อมโยงกันเป็นกราฟ แต่ REST บังคับให้คิดเป็น resource URL ซึ่งไม่ตรงกับวิธีที่สมองมองข้อมูล ชื่อ GraphQL ก็มาจากตรงนี้

Facebook ใช้ GraphQL ใน production บน iOS ตั้งแต่ปี 2012 จากนั้นเปิดเป็น open source ในปี 2015 และปี 2018 ย้ายไปอยู่ภายใต้ GraphQL Foundation ซึ่ง host โดย Linux Foundation — ทำให้ตอนนี้เป็นมาตรฐานกลางที่ไม่ได้ผูกกับบริษัทใดบริษัทหนึ่ง


⚙️ query กับ mutation — สองคำสั่งหลัก#

ในทางปฏิบัติ GraphQL มี operation หลักอยู่สองแบบ

query คือการอ่านข้อมูล เทียบได้กับ GET ของฝั่ง REST — ขอข้อมูลมาแสดง

mutation คือการเปลี่ยนแปลงข้อมูล ไม่ว่าจะ create, update หรือ delete รวมถึง operation ที่มี side effect อย่างการสร้าง record ใหม่หรือส่ง email โดยทั่วไป mutation มักรับข้อมูลเข้าผ่าน Input object type เพื่อให้ส่ง argument เป็นก้อนเดียวสะอาด ๆ

ลองดูหน้าตา query จริง สมมติอยากได้รายชื่อหนังสือพร้อมชื่อคนเขียน

query GetBooks {
  books {
    title
    author
  }
}
graphql

สังเกตว่าเราระบุ title กับ author เอง — response ที่กลับมาก็จะมีแค่สองอันนี้ ถ้าวันหลังอยากได้ปีที่พิมพ์เพิ่ม ก็แค่เติม year เข้าไปใน query โดยไม่ต้องไปแก้ฝั่ง server ตราบใดที่ schema มี field นั้นอยู่แล้ว


🌍 ใครใช้จริงบ้าง#

ของแบบนี้เห็นภาพง่ายสุดเมื่อดูว่าคนเอาไปใช้ทำอะไร

Shopify เปิดให้ third-party developer ดึงรายละเอียดสินค้าและระดับ inventory ทั้งหมดได้ในคำขอเดียว แทนที่จะต้องยิงหลาย request ไปหลาย endpoint รวมถึงจัดการตะกร้าสินค้าได้ด้วย

platform ที่มี mobile app มักใช้ GraphQL เพื่อขอเฉพาะ field ที่หน้าจอนั้น ๆ ต้องการจริง ๆ เช่น หน้า feed อยากได้แค่รูปกับ metadata ก็ query แค่นั้น ไม่ต้องรับ payload ทั้งก้อน ประหยัด bandwidth บนมือถือได้ชัดเจน

จุดร่วมของทุกเคสคือ — ขอเท่าที่ใช้ ส่งเท่าที่ขอ ไม่เปลือง round-trip และไม่เปลือง data


💻 implement ยังไง#

ฝั่ง implement มีให้เลือกแทบทุกภาษา ขอยกสองตัวที่นิยม

Node.js ใช้ Apollo Server เป็นแนว schema-first คือนิยาม schema ก่อน แล้วเขียน resolver (ฟังก์ชันที่บอกว่าแต่ละ field เอาข้อมูลมาจากไหน)

const typeDefs = `#graphql
  type Book { title: String, author: String }
  type Query { books: [Book] }
`;

const resolvers = {
  Query: { books: () => books },
};

const server = new ApolloServer({ typeDefs, resolvers });
await startStandaloneServer(server, { listen: { port: 4000 } });
javascript

Apollo Server เป็น open-source GraphQL server ที่ spec-compliant ทำงานร่วมกับ Express, Connect, Hapi, Koa ได้ และเป็นวิธีที่นิยมในการสร้าง GraphQL API ระดับ production

Python ใช้ Strawberry เป็นแนว code-first คือใช้ Python type hints กับ decorator สร้าง schema จากโค้ดเลย ลด boilerplate และจับ error ได้ตั้งแต่ตอน development

@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"

schema = strawberry.Schema(query=Query)
python

นอกจาก Strawberry ยังมี Graphene เป็นอีกตัวเลือก ทั้งคู่ใช้ร่วมกับ FastAPI, Flask, Django ได้หมด ต่างกันตรง Strawberry เขียนน้อยกว่าเพราะอาศัย type hints ส่วน Graphene ต้องเขียน boilerplate มากกว่า


✅ ข้อดี#

ดึงข้อมูลแม่นยำ — ได้เฉพาะที่ขอ ไม่มี over-fetching และรวมหลาย resource ในคำขอเดียวได้ ลด round-trip ลงเยอะ

strong typing ผ่าน schema — schema ทำตัวเป็น contract ที่ frontend กับ backend ยึดร่วมกัน บวกกับ introspection ที่เปิดดูโครงสร้าง API ได้ในตัว

evolve API ได้โดยไม่ต้อง versioning — แทนที่จะออก /v2 ใหม่ทั้งชุด GraphQL ใช้วิธีเพิ่ม field ใหม่หรือ deprecate field เก่าภายใน schema เดิม ทำให้ค่อย ๆ เปลี่ยนได้ราบรื่นกว่า

โดยรวมจึงเข้าทางกับงาน mobile/web ที่อยากลด data transfer และ domain ที่มี object หลายชนิดเชื่อมโยงกัน เช่น e-commerce


⚠️ ข้อเสียและจุดที่ต้องระวัง#

ของดีย่อมมีราคา GraphQL ก็มีต้นทุนที่ต้องรู้ก่อน

ซับซ้อนกว่า REST ตั้งแต่ตอน setup ไปจนถึง error handling ที่ยุ่งกว่า ต้องลงแรงเรียนรู้พอสมควร

HTTP caching ทำได้ยาก เพราะใช้ endpoint เดียวและโดยปกติยิงผ่าน POST ซึ่งโดยค่าเริ่มต้นไม่ cacheable REST ได้เปรียบเรื่องนี้ชัดเจน เพราะอาศัย HTTP semantics มาตรฐาน เข้ากับ browser cache, reverse proxy และ CDN ผ่าน Cache-Control กับ ETag ได้เลย

query ลึก ๆ แพงและถูก abuse ได้ เพราะ client เขียน query เองได้ ใครยิง query ที่ซ้อนลึกมาก ๆ ก็อาจทำ server อ่วมได้ ต้องทำ query cost analysis กับ depth limiting กันไว้

แล้วมี gotcha ตัวฉกาจที่เจอกันบ่อยสุดคือ N+1 query problem — เวลา resolver ดึง child record server อาจเผลอยิง DB query แยกทีละ record ทำให้จำนวน DB call ระเบิด ทางแก้มาตรฐานคือใช้ DataLoader ซึ่งทำหน้าที่ batch คำขอซ้ำ ๆ เข้าด้วยกันแล้ว cache ผลภายใน query เดียว

อีกเรื่องคือ client cache ถ้าไม่ normalize ให้ดีก็ทำให้ข้อมูลซ้ำและ UI ไม่สอดคล้องกัน หรือตั้ง fetchPolicy ผิดก็ได้ข้อมูล stale เรื่อง cache invalidation จึงเป็นภาระที่ต้องดูแลต่อเนื่อง


🚦 เมื่อไหร่ที่ไม่ควรใช้#

GraphQL ไม่ใช่คำตอบของทุกงาน บางสถานการณ์ REST ธรรมดากลับเหมาะกว่า

  • ข้อมูลเป็น flat หรือ CRUD ง่าย ๆ ไม่ได้มีความสัมพันธ์ซับซ้อน
  • ต้องการ HTTP caching แบบ aggressive (เช่น public API ที่อยากให้ CDN ช่วยแบกโหลด)
  • ทีมยังไม่มีประสบการณ์ GraphQL การเพิ่มความซับซ้อนตอนนี้อาจไม่คุ้ม
  • มี frontend เดียวที่ความต้องการข้อมูลคาดเดาได้ตายตัว หรือมี entity น้อย

ในเคสเหล่านี้ ทางเลือกที่ควรพิจารณาคือ REST/OpenAPI สำหรับงาน CRUD และ public API ที่อยากได้ compatibility กว้าง ๆ, tRPC สำหรับงาน full-stack TypeScript ที่อยากได้ type safety โดยไม่ต้อง codegen (แต่ใช้ได้เฉพาะตอน client เป็น TS), และ gRPC สำหรับการคุยกันระหว่าง service ปริมาณสูงด้วย Protobuf


🧭 สรุป#

GraphQL พลิกวิธีคิดเรื่อง API จาก “server กำหนดว่าจะส่งอะไร” เป็น “client บอกเองว่าอยากได้อะไร” ผ่าน endpoint เดียวบน schema ที่ strongly typed ทำให้แก้ปัญหา over-fetching กับ under-fetching ของ REST ได้ตรงจุด และรวมหลาย resource ในคำขอเดียวได้

แต่ความยืดหยุ่นนี้แลกมาด้วยความซับซ้อน — caching ที่ยากขึ้น, N+1 problem ที่ต้องคอยจัดการ และ query ที่ต้องป้องกันการ abuse ของพวกนี้ไม่ใช่อุปสรรคที่ข้ามไม่ได้ แต่ต้องรู้ตัวก่อนว่าจะเจอ

ทางที่ดีคือ — ถ้า domain ของคุณมี object หลายชนิดเกี่ยวพันกัน มี client หลายแบบที่ต้องการข้อมูลต่างกัน และทีมพร้อมเรียนรู้ GraphQL คุ้มค่าที่จะลอง แต่ถ้างานเป็น CRUD ตรงไปตรงมา REST ก็ยังทำงานได้ดีและเรียบง่ายกว่ามาก

อยากลองต่อ ลองหยิบ Apollo Server หรือ Strawberry มาตั้ง /graphql เล็ก ๆ สักตัว เขียน query แรกแล้วดูว่าได้กลับมาเฉพาะ field ที่ขอจริงไหม

😎 ☕

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

GraphQL คืออะไร — ทำไม client ถึงขอข้อมูลเองได้
Author Coffee Stack
Published at 25 มิถุนายน 2026