Search & Envelopes
ของสองอย่างปิดท้ายที่ทำให้ endpoint แบบ collection ใช้งานลื่นขึ้น คือ parameter สำหรับ search แบบ free-text และรูปร่าง envelope ชุดเดียวที่ทุก collection ใช้ร่วมกัน
Search เทียบกับ structured filter
หัวข้อที่มีชื่อว่า “Search เทียบกับ structured filter”parameter ?q= มีไว้สำหรับการ search แบบ fuzzy ที่เป็น free-text ทั่วทั้ง resource (“อะไรก็ตามที่ตรงกับ graphql”):
GET /articles?q=graphqlstructured filter (?status=published) ตอบคำถามที่ชัดเจน ส่วน search ตอบคำถามที่คลุมเครือ ทั้งสองทำงานร่วมกันได้ — ?q=graphql&status=published คือการ search ภายในชุดที่ filter มาแล้ว แต่ต้องแยกบทบาทให้ชัด: q เป็น fuzzy มีการจัดอันดับ (ranked) และอาจมี search engine อยู่เบื้องหลัง ส่วน filter เป็น predicate ที่แม่นยำ
envelope ที่สม่ำเสมอ
หัวข้อที่มีชื่อว่า “envelope ที่สม่ำเสมอ”ทุก response แบบ collection ควรใช้ wrapper เดียวกัน เพื่อให้ client เขียน code จัดการการแบ่งหน้าเพียงครั้งเดียว:
ต้นทุนของการนับจำนวนรวม
หัวข้อที่มีชื่อว่า “ต้นทุนของการนับจำนวนรวม”การคืน total นั้นสะดวก แต่บนตารางขนาดใหญ่ การนับทุกแถวที่ตรงเงื่อนไขอาจมีต้นทุนพอ ๆ กับตัว query เอง ทางเลือก: cache จำนวนนับไว้ คืนจำนวนแบบโดยประมาณ หรือไม่คืนเลย (cursor pagination มักทำแบบนี้ — ให้แค่ next โดยไม่มียอดรวม)
| ข้อดี (Response Envelope) | ข้อแลกเปลี่ยน |
|---|---|
| metadata (pagination, total) รวมอยู่ใน response เดียว | verbose กว่า bare array |
| consistent structure ทุก collection endpoint | client ต้อง unwrap data ทุกครั้ง |
| ง่ายต่อการเพิ่ม metadata ในอนาคตโดยไม่ breaking | bare array ง่ายกว่าสำหรับ simple use case |
search result มี meta.total, meta.took ใน envelope |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”Search ที่ไม่ต่างจาก Filter อาการ:
GET /users?search=john— query ทุก field ด้วย LIKE ‘%john%’- slow บน large table, ไม่ rank ตาม relevance
- search จริงควรใช้ full-text search engine (Elasticsearch, PostgreSQL FTS)
Envelope ที่ Inconsistent อาการ:
GET /usersreturn{ "data": [...], "meta": {...} }GET /productsreturn{ "items": [...], "pagination": {...} }- กำหนด envelope มาตรฐานและใช้ทุก collection endpoint
💡 ตัวอย่างจากของจริง
GitHub API:
- search:
GET /search/repositories?q=rest+api+language:javascript&sort=stars- envelope:
{ "total_count": 12345, "incomplete_results": false, "items": [...] }Stripe API:
- envelope สม่ำเสมอ:
{ "object": "list", "data": [...], "has_more": true, "url": "/charges" }- ทุก list endpoint ใช้ format เดียวกัน