ข้ามไปยังเนื้อหา

Search & Envelopes

ของสองอย่างปิดท้ายที่ทำให้ endpoint แบบ collection ใช้งานลื่นขึ้น คือ parameter สำหรับ search แบบ free-text และรูปร่าง envelope ชุดเดียวที่ทุก collection ใช้ร่วมกัน

parameter ?q= มีไว้สำหรับการ search แบบ fuzzy ที่เป็น free-text ทั่วทั้ง resource (“อะไรก็ตามที่ตรงกับ graphql”):

GET /articles?q=graphql

structured filter (?status=published) ตอบคำถามที่ชัดเจน ส่วน search ตอบคำถามที่คลุมเครือ ทั้งสองทำงานร่วมกันได้ — ?q=graphql&status=published คือการ search ภายในชุดที่ filter มาแล้ว แต่ต้องแยกบทบาทให้ชัด: q เป็น fuzzy มีการจัดอันดับ (ranked) และอาจมี search engine อยู่เบื้องหลัง ส่วน filter เป็น predicate ที่แม่นยำ

ทุก response แบบ collection ควรใช้ wrapper เดียวกัน เพื่อให้ client เขียน code จัดการการแบ่งหน้าเพียงครั้งเดียว:

JavaScript

การคืน total นั้นสะดวก แต่บนตารางขนาดใหญ่ การนับทุกแถวที่ตรงเงื่อนไขอาจมีต้นทุนพอ ๆ กับตัว query เอง ทางเลือก: cache จำนวนนับไว้ คืนจำนวนแบบโดยประมาณ หรือไม่คืนเลย (cursor pagination มักทำแบบนี้ — ให้แค่ next โดยไม่มียอดรวม)

ข้อดี (Response Envelope)ข้อแลกเปลี่ยน
metadata (pagination, total) รวมอยู่ใน response เดียวverbose กว่า bare array
consistent structure ทุก collection endpointclient ต้อง unwrap data ทุกครั้ง
ง่ายต่อการเพิ่ม metadata ในอนาคตโดยไม่ breakingbare 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 /users return { "data": [...], "meta": {...} }
  • GET /products return { "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 เดียวกัน
`?q=` ต่างจาก structured filter อย่าง `?status=published` อย่างไร?
ทำไมการคืนจำนวนนับ `total` จึงอาจมีต้นทุนสูง?
ประโยชน์ของการมี envelope ของ collection ที่ใช้ร่วมกันชุดเดียวคืออะไร?