Một SDK viết bằng TypeScript dành cho API của Sapo, cung cấp các phương thức tiện lợi để xác thực và thao tác với API.
# Sử dụng npm
npm install sapo-client-sdk
# Sử dụng yarn
yarn add sapo-client-sdk
# Sử dụng pnpm
pnpm add sapo-client-sdk
Tạo file .env
ở thư mục gốc của dự án:
SAPO_API_KEY=your_api_key
SAPO_SECRET_KEY=your_secret_key
SAPO_REDIRECT_URI=https://your-app.com/oauth/callback
import { SapoClient } from 'sapo-client-sdk';
// Khởi tạo client
const client = new SapoClient({
type: 'private',
store: 'your-store.mysapo.net',
apiKey: 'your-api-key',
apiSecret: 'your-secret-key',
});
// Lấy URL để người dùng xác thực OAuth
const authUrl = client.getAuthorizationUrl({
store: 'your-store.mysapo.net',
scopes: ['read_products', 'write_products'],
});
// Sau khi xác thực, hoàn tất quy trình OAuth
const token = await client.completeOAuth('your-store.mysapo.net', 'callback-url-with-code');
// Gọi API
try {
const products = await client.get('/admin/products.json');
console.log(products);
} catch (error) {
console.error('Lỗi API:', error);
}
SDK hỗ trợ quy trình xác thực theo chuẩn OAuth 2.0. Các bước triển khai như sau:
const client = new SapoClient({
type: 'private',
store: 'your-store.mysapo.net',
apiKey: process.env.SAPO_API_KEY,
apiSecret: process.env.SAPO_SECRET_KEY,
});
const authUrl = client.getAuthorizationUrl({
store: 'your-store.mysapo.net',
scopes: ['read_products', 'write_products'],
state: 'optional-state-parameter', // Tùy chọn để bảo vệ CSRF
});
// Chuyển hướng người dùng tới authUrl
app.get('/oauth/callback', async (req, res) => {
try {
const token = await client.completeOAuth(
'your-store.mysapo.net',
req.url // URL callback chứa mã xác thực
);
// Lưu token một cách an toàn
await saveToken(token);
res.redirect('/dashboard');
} catch (error) {
console.error('Lỗi OAuth:', error);
res.redirect('/error');
}
});
// Lưu token
const token = await client.completeOAuth(...);
client.setToken(token);
// Kiểm tra token hết hạn
if (client.isTokenExpired()) {
// Làm mới token
const newToken = await client.refreshToken(token.refresh_token);
client.setToken(newToken);
}
SDK sử dụng thuật toán token bucket để giới hạn tốc độ theo yêu cầu của Sapo:
SDK sẽ tự động quản lý việc giới hạn tốc độ và xếp hàng các yêu cầu nếu cần:
const client = new SapoClient({...});
for (let i = 0; i < 100; i++) {
await client.get('/admin/products.json'); // SDK sẽ tự xếp hàng các yêu cầu
}
Bạn có thể tự kiểm tra trạng thái giới hạn:
const limits = client.getRateLimits();
console.log({
remaining: limits.remaining, // Số yêu cầu còn lại
limit: limits.limit, // Tổng giới hạn
reset: limits.reset, // Thời gian reset tiếp theo
});
Xử lý lỗi do vượt quá giới hạn:
try {
await client.get('/admin/products.json');
} catch (error) {
if (error instanceof RateLimitError) {
console.log('Vượt quá giới hạn gọi API');
console.log('Thử lại sau:', error.retryAfter, 'giây');
}
}
SDK cung cấp các class lỗi được định nghĩa để dễ xử lý:
import {
SapoError,
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError,
NetworkError,
} from 'sapo-client-sdk';
try {
await client.get('/admin/products.json');
} catch (error) {
if (error instanceof AuthenticationError) {
console.log('Xác thực thất bại:', error.message);
} else if (error instanceof RateLimitError) {
console.log('Quá giới hạn, thử lại sau:', error.retryAfter);
} else if (error instanceof ValidationError) {
console.log('Lỗi xác thực dữ liệu:', error.errors);
} else if (error instanceof NotFoundError) {
console.log('Không tìm thấy tài nguyên:', error.message);
} else if (error instanceof NetworkError) {
console.log('Lỗi mạng:', error.message);
} else if (error instanceof SapoError) {
console.log('Lỗi từ API:', error.message, error.code);
}
}
SDK hỗ trợ đầy đủ các thao tác với webhook:
const webhooks = client.webhooks;
// Tạo webhook mới
const webhook = await webhooks.create({
topic: 'orders/create',
address: 'https://your-app.com/webhooks',
format: 'json',
});
// Danh sách webhook đang hoạt động
const activeWebhooks = await webhooks.list();
// Cập nhật webhook
await webhooks.update(webhook.id, {
address: 'https://new-address.com/webhooks',
});
import express from 'express';
const app = express();
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-sapo-hmac-sha256'];
const body = req.body.toString();
if (!client.webhooks.verifySignature(signature, body)) {
return res.status(401).send('Chữ ký không hợp lệ');
}
const webhook = JSON.parse(body);
console.log('Webhook nhận được:', webhook);
res.status(200).send('OK');
});
// Danh sách lịch sử gửi webhook
const deliveries = await webhooks.listDeliveries(webhookId);
// Xem chi tiết một lần gửi
const delivery = await webhooks.getDelivery(webhookId, deliveryId);
// Gửi lại nếu thất bại
await webhooks.resendDelivery(webhookId, deliveryId);
// Test webhook
await webhooks.test(webhookId);
Tham khảo thêm tại:
Phát hành theo giấy phép MIT – xem file LICENSE để biết thêm chi tiết.