Phân trang
Endpoint danh sách trả kết quả từng trang, mới nhất trước, theo kiểu phân trang theo khoá (keyset): bạn xin trang nằm ngay sau phần tử cuối cùng bạn đang có. Khác với số trang, cách này vẫn đúng khi phần tử mới liên tục được thêm vào. Trang này giải thích tham số, các trường trong response và cách duyệt hết một danh sách.
Tham số
| Tham số | Ý nghĩa |
|---|---|
limit | Số phần tử cần trả. Giá trị mặc định và tối đa tuỳ danh sách (xem bên dưới). Giá trị ngoài khoảng nhận 422 validation_error. |
after | id của phần tử cuối ở trang trước. Response bắt đầu ngay sau phần tử đó. Bỏ trống ở trang đầu. |
GET /emails nhận thêm before, là id của một phần tử, để lấy các phần tử mới hơn nó.
Response
Mọi danh sách trả về cùng một dạng:
{
"object": "list",
"has_more": true,
"next_cursor": "pay_01a0b904297873e8b3524a26fdca0ab5",
"data": [
{ "object": "payment", "id": "pay_01a0b904...", "status": "paid" },
{ "object": "payment", "id": "pay_01a0b903...", "status": "pending" }
]
}
| Trường | Ý nghĩa |
|---|---|
data | Các phần tử của trang này |
has_more | true khi còn ít nhất một trang nữa |
next_cursor | Chỉ có ở danh sách của Thanh toán: giá trị truyền vào after để lấy trang tiếp, hoặc null ở trang cuối. Đó là id của phần tử cuối trong data. |
Với danh sách không có next_cursor, truyền id của phần tử cuối trong data vào after. Kết quả như nhau.
Giới hạn theo từng danh sách
| Danh sách | limit mặc định | Tối đa |
|---|---|---|
| Email: email, thư đến, liên hệ, template, logs | 20 | 100 |
| Thanh toán: thanh toán, giao dịch, hoá đơn điện tử | 20 | 100 |
| Hỗ trợ: hội thoại | 50 | 100 |
| Hỗ trợ, Sản phẩm và CRM: phiếu hỗ trợ, sản phẩm, đơn hàng, khách hàng | 50 | 200 |
Một vài danh sách nhỏ như tên miền, webhook và chiến dịch email trả mọi phần tử trong một response.
Tin nhắn của hội thoại phân trang theo cách khác, bằng số thứ tự: GET /chat/conversations/{id}/messages nhận after_seq (seq của tin nhắn cuối bạn đang có) và limit tối đa 200, mặc định 100. Đây là cách đồng bộ một hội thoại theo từng phần mới.
Duyệt hết một danh sách
Lấy một trang, xử lý, rồi tiếp tục khi has_more còn là true:
- cURL
- Node.js
- Python
- PHP
# Trang đầu
curl "https://api.hatang.dev/payments?limit=100" \
-H "Authorization: Bearer $HATANG_API_KEY"
# Trang tiếp: truyền next_cursor (hoặc id cuối) vào after
curl "https://api.hatang.dev/payments?limit=100&after=pay_01a0b904297873e8b3524a26fdca0ab5" \
-H "Authorization: Bearer $HATANG_API_KEY"
import { Hatang } from "@hatang/sdk";
const hatang = new Hatang(process.env.HATANG_API_KEY, { baseUrl: "https://api.hatang.dev" });
async function* allEmails() {
let after;
while (true) {
const { data: page, error } = await hatang.emails.list({ limit: 100, after });
if (error) throw new Error(`${error.name}: ${error.message}`);
yield* page.data;
if (!page.has_more || page.data.length === 0) return;
after = page.data[page.data.length - 1].id;
}
}
for await (const email of allEmails()) {
console.log(email.id, email.last_event);
}
from hatang import Hatang
hatang = Hatang() # đọc HATANG_API_KEY
def all_payments():
after = None
while True:
page = hatang.payments.list(limit=100, after=after)
yield from page["data"]
if not page["has_more"]:
return
after = page.get("next_cursor") or page["data"][-1]["id"]
for payment in all_payments():
print(payment["id"], payment["status"])
function allConversations(GuzzleHttp\Client $client): Generator {
$query = ['limit' => 100];
do {
$page = json_decode((string) $client->get('/chat/conversations', ['query' => $query])->getBody(), true);
yield from $page['data'];
$last = end($page['data']);
$query['after'] = $last ? $last['id'] : null;
} while ($page['has_more'] && $last);
}
foreach (allConversations($client) as $conversation) {
echo $conversation['id'], PHP_EOL;
}
Bộ lọc như status giữ nguyên ở mọi trang: gửi kèm trong từng request cùng với after. Mỗi trang là một request tính vào giới hạn tần suất, nên hãy dùng limit lớn nhất mà bạn xử lý được.