คู่มือ API
เรียก API ของแพลตฟอร์มด้วย bearer token หรือ API key รู้ว่าแต่ละ endpoint อยู่ที่ path ไหน ข้อผิดพลาดหน้าตาอย่างไร และแบ่งหน้าอย่างไร
API ทั้งหมดของแพลตฟอร์มอยู่ที่ <site>/api/... และทุกคำขอต้องมี bearer token หรือ API key <site> ในหน้านี้คือที่อยู่ของแพลตฟอร์มคุณ เช่น https://platform.example.com
ลองเรียกดู
curl -H "X-API-Key: $KEY" https://platform.example.com/api/profileถ้าได้โปรไฟล์ของเจ้าของคีย์กลับมา คีย์ใช้ได้
ที่อยู่
แต่ละ path ขึ้นต้นเป็นของโหนดหนึ่ง ตารางของแต่ละโหนดมีทุก endpoint
| path | โหนด |
|---|---|
/api/auth | authorization-server ออก token ดู bearer token จาก OAuth client |
/api/item | item-services ทำงานกับรายการและระเบียน และ tile-services ส่ง tile ใต้ /api/item/:id/actions/getTile |
/api/file | file-services ส่งไฟล์ |
/api/realtime | realtime-services ส่งเหตุการณ์ผ่าน socket.io |
/api ที่เหลือ | core-services ผู้ใช้งาน กลุ่ม Drive โปรไฟล์ และการจัดการ |
item-services ส่งเอกสาร OpenAPI ที่สร้างจากโค้ดให้ที่ /api/item/openapi/openapi.json และหน้าดูที่ /api/item/openapi/ui สองตัวนี้ไม่ต้องลงชื่อเข้าใช้
การยืนยันตัวตน
ส่งข้อมูลยืนยันตัวตนใน header เสมอ ไม่ใส่ใน URL เพราะ URL ถูกบันทึกไว้ในหลายที่ ไม่มีวิธีอื่น: endpoint ไม่รับชื่อผู้ใช้และรหัสผ่าน และไม่เชื่อ header x-auth-*
| วิธี | header | ใช้เมื่อ |
|---|---|---|
| bearer token | Authorization: Bearer <token> | แอปที่ให้คนลงชื่อเข้าใช้ และทำงานแทนเขา |
| API key | X-API-Key: <key> | โปรแกรมที่ทำงานเอง ไม่มีคนลงชื่อเข้าใช้ |
| ลิงก์ที่เซ็นชื่อ | ไม่มี มี sig ใน URL | แสดงหรือดาวน์โหลดไฟล์ใน <img> หรือลิงก์ |
bearer token จาก OAuth client
คุณต้องมี OAuth client ก่อน สร้างได้ใน Account (OAuth client) หรือผู้ดูแลระบบสร้างให้ (OAuth client ของแพลตฟอร์ม) จดค่า Client ID และ redirect URI ที่ลงทะเบียนไว้ แล้วทำตามนี้ โดยใช้ PKCE
-
สร้างค่า
code_verifierแบบสุ่ม และคำนวณcode_challengeจากมันverifier=$(openssl rand -base64 48 | tr -d '=+/' | cut -c1-64) challenge=$(printf %s "$verifier" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=') -
ส่งผู้ใช้งานไปที่หน้าลงชื่อเข้าใช้
redirect_uriต้องขึ้นต้นด้วยค่าที่ลงทะเบียนไว้ใน clienthttps://platform.example.com/api/auth/oauth2/authorize ?response_type=code &client_id=my-app &redirect_uri=https://app.example.com/callback &code_challenge=<challenge> &code_challenge_method=sha256 &state=<ค่าสุ่ม> -
หลังลงชื่อเข้าใช้ เบราว์เซอร์กลับมาที่
redirect_uriพร้อมcodeและstateให้ตรวจstateว่าเป็นค่าที่คุณส่งไป -
แลก
codeเป็น tokencurl -s https://platform.example.com/api/auth/oauth2/token \ -d grant_type=authorization_code \ -d client_id=my-app \ -d code="$CODE" \ -d code_verifier="$verifier" \ -d redirect_uri=https://app.example.com/callback{ "access_token": "…", "refresh_token": "…", "expires_in": 86400, "token_type": "Bearer" } -
เรียก API ด้วย
Authorization: Bearer <access_token>
access_token อยู่ได้ประมาณหนึ่งวัน (expires_in เป็นวินาที) refresh_token อยู่ได้ประมาณ 30 วัน และใช้ได้ครั้งเดียว ต่ออายุด้วย
curl -s https://platform.example.com/api/auth/oauth2/token \
-d grant_type=refresh_token -d client_id=my-app \
-d refresh_token="$REFRESH" -d code_verifier="$verifier"ถ้าฝั่งเซิร์ฟเวอร์เก็บความลับได้ ให้ส่ง client_secret แทน code_verifier ใน body หรือใช้ HTTP Basic (client_id:client_secret) กับ endpoint /oauth2/token เท่านั้น ถอน token ด้วย POST /api/auth/oauth2/revoke และ body token=<access_token>
API key
สร้างใน Account (API key ส่วนตัว) หรือผู้ดูแลระบบสร้างให้ (API key ของแพลตฟอร์ม) คีย์ทำงานแทนเจ้าของคีย์ และทำได้เท่าที่ scope ของคีย์ให้
| scope | ทำได้ |
|---|---|
public:reader | อ่านเนื้อหาสาธารณะ |
items:reader | อ่านรายการที่เป็นของเจ้าของคีย์หรือแชร์ให้เขา |
items:organizer | จัดการรายการที่เป็นของเจ้าของคีย์ |
groups:reader, groups:organizer | อ่าน หรือจัดการ กลุ่มของเจ้าของคีย์ |
admin:reader, admin:organizer | อ่าน หรือจัดการ ข้อมูลของผู้ดูแลระบบ เช่น ผู้ใช้งาน บทบาท client และ API key |
GET /api/credential/scope แสดงรายการ scope ทั้งหมดของเวอร์ชันนี้ endpoint ใต้ /api/admin ต้องการคีย์ที่มี scope ขึ้นต้นด้วย admin และเจ้าของคีย์ต้องมีสิทธิ์ผู้ดูแลระบบ
ลิงก์ที่เซ็นชื่อ
ไฟล์ใน <img> หรือลิงก์ดาวน์โหลดส่ง header ไม่ได้ ให้ขอลิงก์จาก file-services ด้วย token หรือ API key ของคุณ
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"files":[{"id":"<id ของไฟล์>","use":"content"}]}' \
https://platform.example.com/api/file/linksuse เป็น content (แสดงในหน้า) download (บันทึก) หรือ thumbnail พร้อม width เป็นหนึ่งใน 160, 320, 640, 1280 และ 2048 คำตอบมี links ของแต่ละไฟล์ และ denied ซึ่งเป็น id ของไฟล์ที่คุณอ่านไม่ได้ ลิงก์เป็น path ที่ขึ้นต้นด้วย /api/file/ และมี sig ใช้กับ GET ธรรมดาได้เลย ไม่ต้องมี header จนถึงสิ้นชั่วโมงถัดไป (ระหว่างหนึ่งถึงสองชั่วโมง) คีย์ของระบบขอลิงก์ไม่ได้ เพราะลิงก์ต้องผูกกับผู้ใช้งานคนหนึ่ง
ระดับในรายการ
endpoint ใต้ /api/item/:id ดูว่าคุณมีระดับอะไรในรายการนั้น ตารางใน item-services เขียนระดับต่ำสุดที่ต้องมี และระดับที่สูงกว่าทำได้ด้วย
| ระดับในตาราง | ระดับในแอป |
|---|---|
reader | ผู้อ่าน |
writer | ผู้เขียน |
itemOrganizer | คนจัดการรายการ |
ระดับเหล่านี้ตั้งตอนแชร์ ดู แชร์ คีย์ที่ไม่มี scope items:organizer ทำอะไรที่ต้องการระดับสูงกว่า reader ไม่ได้
ข้อผิดพลาด
ทุกโหนดตอบด้วยรหัส HTTP และ body แบบ JSON ที่ต่างกันเล็กน้อย
| โหนด | body |
|---|---|
| core-services | { "errors": [ { "code": "FORBIDDEN", "message": "Forbidden." }, { "message": "INSUFFICIENT_PERMISSION" } ] } รายการแรกคือชนิด รายการหลังบอกเหตุผล |
| item-services | { "message": "Not found", "code": 404, "type": "NOT_FOUND_ITEM" } code คือรหัส HTTP และ type บอกเหตุผล |
| file-services | { "message": "Not found", "code": 404, "type": "NOT_FOUND_FILE" } ถ้าเป็น 5xx type เป็น INTERNAL_ERROR เท่านั้น |
รหัสที่พบบ่อย
| รหัส | เมื่อ | เหตุผลที่พบ |
|---|---|---|
| 401 | ไม่มีข้อมูลยืนยันตัวตน หรือใช้ไม่ได้ | INVALID_TOKEN, EXPIRED_TOKEN, INVALID_API_KEY, EXPIRED_API_KEY, INVALID_AUTH_TYPE |
| 403 | ยืนยันตัวตนแล้ว แต่ไม่มีสิทธิ์ | INSUFFICIENT_SCOPE, INSUFFICIENT_PERMISSION |
| 404 | ไม่พบสิ่งที่ขอ หรือคุณเห็นไม่ได้ | NOT_FOUND_ITEM, NOT_FOUND_FILE |
| 405 | ใช้เมธอดที่ path นั้นไม่รับ |
/api/file ตอบ 404 เหมือนกันทั้งไฟล์ที่ไม่มีและไฟล์ที่คุณอ่านไม่ได้ เพื่อไม่ให้ใครเดา id
การแบ่งหน้า
endpoint ที่แสดงรายการส่วนใหญ่รับ skip และ limit ทาง query string ของ GET หรือใน body ของ POST ค่าเริ่มต้นคือ limit 10 และ limit=0 คือไม่จำกัด รับ keyword สำหรับค้นหา sort เป็น JSON เช่น {"name":1} และ query เป็น JSON ของเงื่อนไข
curl -H "X-API-Key: $KEY" \
"https://platform.example.com/api/admin/user?keyword=somchai&skip=20&limit=10"คำตอบของ core-services และ item-services มี total (จำนวนทั้งหมดที่ตรงเงื่อนไข) และ data (หน้านี้)
{ "total": 134, "data": [ … ] }