ข้ามไปยังเนื้อหา
Pre-MVP โค้ดเบส 1.0 ยังไม่ใช่ผลิตภัณฑ์ที่เผยแพร่ — ดู ขอบเขตผลิตภัณฑ์ 1.0

API อ่านข้อมูลสาธารณะ (v1)

ทุก endpoint ด้านล่างระบุไซต์จาก header Host และจากสิ่งนั้นเท่านั้น ไม่มีพารามิเตอร์ระบุไซต์ ไม่มี header ระบุไซต์ และผู้เรียกไม่มีทางเลือกไซต์ได้เลย — ซึ่งทำให้การอ่านข้ามไซต์เป็นไปไม่ได้ในเชิงโครงสร้าง แทนที่จะเป็นเพียงสิ่งที่ถูกห้าม

host นี้ให้บริการไซต์อยู่หรือไม่ ตอบเฉพาะ host ที่ deployment นี้รู้จักเท่านั้น host ที่ไม่รู้จักจะได้ 404 ที่นี่เหมือนกับทุกที่อื่นทุกประการ ดังนั้นจึงใช้ endpoint นี้ค้นหาว่ามีไซต์ใดอยู่บ้างไม่ได้

Status ความหมาย
200 host นี้ให้บริการไซต์ และ slug ของไซต์อยู่ใน body
404 ไม่มีไซต์ใดตอบบน host นี้
Terminal window
curl https://example.com/health
{ "ok": true, "site": "acme" }

แสดงรายการ item ที่เผยแพร่แล้วของโมเดลหนึ่ง เฉพาะ item ที่เผยแพร่แล้วเท่านั้น การเรียงลำดับ การกรอง และการแบ่งหน้าทั้งหมดเกิดขึ้นในฐานข้อมูล ดังนั้นหน้าหนึ่งจะไม่สั้นกว่า limit แบบเงียบ ๆ เพราะมีบางอย่างถูกตัดทิ้งหลัง query

พารามิเตอร์ จำเป็น ความหมาย
locale ไม่ ภาษาที่จะให้บริการ ค่าเริ่มต้นคือภาษาเริ่มต้นของไซต์ การที่คำแปลที่ขาดหายจะ fallback หรือได้ 404 ขึ้นอยู่กับนโยบาย locale ของไซต์ (SITE) ไม่ใช่พารามิเตอร์นี้ — consumer ไม่สามารถ override ได้ โดยตั้งใจ
limit ไม่ ขนาดหน้า มีเพดานกำหนดโดยเซิร์ฟเวอร์ การขอมากกว่านั้นจะได้ค่าเพดาน
cursor ไม่ เป็นค่าทึบ (opaque) ให้นำมาจาก next_cursor และส่งกลับไปโดยไม่เปลี่ยนแปลง — เนื้อหาภายในไม่ใช่สัญญา และจะเปลี่ยนแปลง
order ไม่ asc, desc — จะอ่านจากปลายด้านใดของรายการ ตามวันที่เผยแพร่ desc คือใหม่สุดก่อนและเป็นค่าเริ่มต้น
relation ไม่ กรองตามฟิลด์ relation ในรูปแบบ relation=field:id ใส่ซ้ำได้ การใส่ซ้ำจะรวมกันแบบ AND ซึ่งเป็นการตีความเดียวที่ให้ consumer จำกัดผลให้แคบลงแทนที่จะขยายออก
tag ไม่ กรองตามฟิลด์ tag ในรูปแบบ tag=field:value ใส่ซ้ำได้ รวมแบบ AND คู่ relation และ tag รวมกันได้ไม่เกิน 16 คู่ต่อ request โดยนับตามจำนวนครั้งที่ใส่ซ้ำ: หากมากกว่านั้นจะถูกปฏิเสธด้วย 400 public_filter_too_many ซึ่งมี max แนบมาด้วย request จะไม่ถูกตัดให้แคบลงแบบเงียบ ๆ เพื่อให้พอดี
Status ความหมาย
200 หน้าหนึ่งของ item ใน data พร้อม page.limit, page.has_more และ page.next_cursor อยู่ข้าง ๆ
400 พารามิเตอร์ที่ endpoint นี้ไม่รับ หรือค่าที่มีรูปแบบผิด
404 ไม่มีโมเดลนี้บนไซต์นี้, host นี้ไม่ได้ให้บริการไซต์ใด หรือ (OR) โมเดลเป็นแบบ private และไม่มี token ที่ถูกต้องส่งมา ใช้คำตอบเดียวสำหรับทุกกรณี โดยตั้งใจ: §7.1 ป้องกันไม่ให้พื้นผิวสาธารณะเปิดเผยโครงสร้างของไซต์ และ 401 จะยืนยันว่าโมเดลนั้นมีอยู่
Terminal window
curl 'https://example.com/v1/article?locale=th&limit=10&order=desc'
{ "data": [ { "id": "ci_…", "slug": "hello", "locale": "th", "fields": { } } ],
"page": { "limit": 10, "has_more": true, "next_cursor": "…" } }

อ่าน item ที่เผยแพร่แล้วหนึ่งรายการ หนึ่ง item ตาม slug slug ไม่ซ้ำกันภายในโมเดลหนึ่งบนไซต์หนึ่ง แต่ไม่ใช่ข้ามไซต์ — ไซต์ถูกกำหนดโดย host และไม่ใช่โดยสิ่งใดที่ผู้เรียกส่งมา

พารามิเตอร์ จำเป็น ความหมาย
locale ไม่ ภาษาที่จะให้บริการ ค่าเริ่มต้นคือภาษาเริ่มต้นของไซต์ การที่คำแปลที่ขาดหายจะ fallback หรือได้ 404 ขึ้นอยู่กับนโยบาย locale ของไซต์ (SITE) ไม่ใช่พารามิเตอร์นี้ — consumer ไม่สามารถ override ได้ โดยตั้งใจ
preview ไม่ preview capability ที่ออกโดย CMS ให้บริการ DRAFT ของ item เพียงหนึ่ง (ONE) รายการ หมดอายุภายในไม่กี่นาที และไม่ถูก cache เด็ดขาด มันไม่ทำให้โมเดลแบบ private อ่านได้ และ preview ที่ถูกปฏิเสธจะตอบ 404 แทน 403 เพื่อให้การปฏิเสธไม่ยืนยันสิ่งใด
Status ความหมาย
200 item นั้น ซึ่งถูก project เป็น locale ที่ร้องขอ
400 พารามิเตอร์ที่ endpoint นี้ไม่รับ
404 ไม่มี item นี้, ยังไม่เผยแพร่, ไม่มีเนื้อหาใน locale ที่นโยบายยอมให้บริการ, preview token ที่ตรวจสอบไม่ผ่าน หรือโมเดลแบบ private ที่ไม่มี token ที่ถูกต้อง ใช้คำตอบเดียวสำหรับทุกกรณี โดยตั้งใจ (§7.1)
Terminal window
curl 'https://example.com/v1/article/hello?locale=th'
{ "data": { "id": "ci_…", "slug": "hello", "locale": "th", "fields": { } } }

โมเดลที่ถูกกำหนดเป็น private จะอ่านได้เฉพาะเมื่อมี site API token ส่งมาในรูปแบบ Authorization: Bearer dw_site_… token ถูกออกในหน้า admin ที่ Settings → Public API มี scope ที่ระบุว่าอ่านโมเดลใดได้บ้าง และ แสดงเพียงครั้งเดียว

request ที่ไม่มี token และ request ที่มี token ผิด จะได้คำตอบที่เหมือนกัน (SAME) นั่น เป็นความตั้งใจ: การแยกแยะทั้งสองกรณีจะบอกผู้เรียกที่ถือค่าที่เดามาว่า โมเดลนั้นมีอยู่

โดยค่าเริ่มต้น API นี้ตอบด้วย no-store: ไม่มีสิ่งใดถูก cache ที่ edge และทุก การอ่านไปถึง worker นี่คือค่าเริ่มต้นเดียวที่ถูกต้องเมื่อไม่มี purge credential

Caching ต้องเปิดใช้เอง การตั้ง PUBLIC_CACHE_MAX_AGE เป็นจำนวนวินาทีที่เป็นบวก — ทั้งบน public Worker และ admin Worker — จะเปิดใช้งาน: จากนั้น response จะถูก cache และติด tag และการเผยแพร่ item หนึ่งจะ purge เฉพาะ response ที่ อ้างถึง item นั้นพอดี ต้องใช้ CF_PURGE_ZONE_ID และ CF_PURGE_API_TOKEN ที่มีสิทธิ์ Zone → Cache Purge หากไม่มี การเปลี่ยนแปลงจะรายงานว่าไม่สามารถล้าง cache ได้ แทนที่จะซ่อนปัญหานั้นไว้

มีสองสิ่งที่ไม่ถูก cache เด็ดขาด ไม่ว่า TTL จะเป็นเท่าใด: response ของ request ที่มี site API token และ preview

เสถียร (STABLE) ภายใน v1: path, ชื่อพารามิเตอร์, ความหมายของ status code และรูปร่างระดับบนสุดของ response — data และบน route แบบรายการ จะมีออบเจกต์ page ที่เก็บ limit, has_more และ next_cursor key ของ item เองคือ id, slug, model, locale, version, published_at, fields, relations และ media

ไม่เสถียร (NOT stable) และห้าม parse: เนื้อหาของ next_cursor, ข้อความที่แน่นอนของ error message และลำดับของ key พารามิเตอร์ทางเลือกใหม่หรือฟิลด์ใหม่ ภายใน item อาจปรากฏขึ้นภายใน v1 ได้ แต่ไม่มีสิ่งใดที่ บันทึกไว้ที่นี่แล้วจะเปลี่ยนความหมายโดยไม่มีเวอร์ชันใหม่ใน path

async function* everyArticle(origin, locale = 'en') {
let cursor;
do {
const url = new URL(`${origin}/v1/article`);
url.searchParams.set('locale', locale);
url.searchParams.set('limit', '50');
// The cursor is opaque. Send back exactly what you were given; do not
// decode it, and do not construct one.
if (cursor) url.searchParams.set('cursor', cursor);
const response = await fetch(url);
if (!response.ok) throw new Error(`${response.status} from ${url}`);
const body = await response.json();
yield* body.data;
// Pagination lives in `page`, beside `data` rather than above it.
cursor = body.page.has_more ? body.page.next_cursor : undefined;
} while (cursor);
}
Terminal window
curl -H "Authorization: Bearer $DEE_WAN_SITE_TOKEN" \
'https://example.com/v1/pricing'

โมเดลแบบ private ที่ไม่มี token ที่ถูกต้องจะตอบ 404 ไม่ใช่ 401 — เป็นคำตอบเดียวกับ โมเดลที่ไม่มีอยู่ นั่นเป็นความตั้งใจ (§7.1): 401 จะยืนยันว่า โมเดลนั้นมีอยู่ และพื้นผิวสาธารณะไม่เปิดเผยสิ่งใดเกี่ยวกับโครงสร้างของไซต์ นั่น ยังหมายความว่า 404 ไม่สามารถตีความว่าเป็น “URL ผิด” ได้ ให้ตรวจสอบ token ก่อน

admin API ที่ต้องยืนยันตัวตนจะส่งออก client ที่ไม่มี dependency สำหรับไซต์ที่เลือก:

Terminal window
curl -H "X-Site-Id: $DEE_WAN_SITE_ID" -b "$DEE_WAN_SESSION_COOKIE" \
'https://admin.example.com/api/models/public-client.ts' \
> src/dee-wan-public.ts

ไฟล์นี้ประกอบด้วย response envelope, locale union, type ของฟิลด์ที่แน่นอน, query type ที่รู้จักโมเดล และ method หนึ่งตัวต่อหนึ่งโมเดล ให้สร้างใหม่หลังจากโมเดลเปลี่ยน Dee Wan ไม่อัปเดต repository ของ consumer

หากคุณเรียก endpoint โดยไม่ใช้ client ที่สร้างขึ้น ให้กำหนด type ของ response envelope และฟิลด์ของโมเดล โดยตรง:

type Item<F> = { id: string; slug: string; locale: string; fields: F };
type Page<F> = {
data: Item<F>[];
page: { limit: number; has_more: boolean; next_cursor: string | null };
};
type Article = { title: string; body: string };
const page: Page<Article> = await (await fetch(url)).json();