Chuyển tới nội dung chính

Hướng dẫn sử dụng Webhook

Cấu hình trên Admin: xem Hướng dẫn Admin — Auth Config và Webhook.

1. Lấy Webhook Config​

Bước 1: Tìm TenantWebhook theo code​

// Cách 1: Dùng TenantWebhookService
Optional<TenantWebhook> webhookOpt = tenantWebhookService.findByTenantIdAndCode(tenantId, "WEBHOOK_CODE");

// Cách 2: Dùng Repository trực tiếp (có filter status)
Optional<TenantWebhook> webhookOpt = tenantWebhookRepository
.findByTenantIdAndCodeAndStatus(tenantId, "WEBHOOK_CODE", TenantWebhookStatus.ACTIVE);
  • tenantId: ID của tenant cần gửi webhook
  • "WEBHOOK_CODE": Khóa định danh của webhook (ví dụ: "NEBULA_SIGNAL_UPDATE")

Bước 2: Lấy danh sách TenantAuthConfig​

TenantWebhook.tenantAuthConfigIds là chuỗi JSON chứa danh sách ID, ví dụ: [1, 2].

TenantWebhook webhookConfig = webhookOpt.get();

List<TenantAuthConfig> authConfigs = new ArrayList<>();
if (webhookConfig.getTenantAuthConfigIds() != null) {
List<Long> authConfigIds = MapperUtils.readValue(
webhookConfig.getTenantAuthConfigIds(),
new TypeReference<List<Long>>() {}
);
if (authConfigIds != null && !authConfigIds.isEmpty()) {
authConfigs = tenantAuthConfigRepository
.findAllByTenantIdAndIdIn(tenantId, authConfigIds);
}
}

2. Gửi Webhook​

Sau khi có webhookConfig và authConfigs, gọi:

webhookService.sendWebhook(tenantId, payload, webhookConfig, authConfigs);

Tham số​

Tham sốKiểuMô tả
tenantIdLongID của tenant
payloadMap<String, List<SignalDataDto>>Dữ liệu gửi đi (key: identifier, value: danh sách data)
webhookConfigTenantWebhookConfig đã lấy ở bước 1
authConfigsList<TenantAuthConfig>Auth configs đã lấy ở bước 2

Hàm sendWebhook() tự động thực hiện​

  1. Kiểm tra trạng thái webhook phải là ACTIVE
  2. Kiểm tra endpoint không null
  3. Serialize payload thành JSON
  4. Áp dụng authentication (API_KEY / BASIC / HMAC) vào header hoặc query param
  5. Tạo bản ghi WebhookExecution để theo dõi
  6. Gửi HTTP POST request với OkHttp3
  7. Cập nhật trạng thái execution (SUCCESS hoặc RETRY_FAILED)
  8. Ghi integration log

Lưu ý: Nếu gửi thất bại, WebhookRetryWorker sẽ tự động retry theo policy đã cấu hình. Không cần xử lý retry thủ công.

3. Ví dụ đầy đủ​

Tham khảo NebulaNotificationServiceImpl.java — ví dụ hoàn chỉnh cách lấy config và gửi webhook:

@Service
@RequiredArgsConstructor
public class MyNotificationServiceImpl {

private static final String MY_WEBHOOK_CODE = "MY_WEBHOOK_CODE";

private final TenantWebhookRepository tenantWebhookRepository;
private final TenantAuthConfigRepository tenantAuthConfigRepository;
private final WebhookService webhookService;

public void sendNotification(Long tenantId, Map<String, List<SignalDataDto>> payload) {
// 1. Lấy webhook config
Optional<TenantWebhook> webhookOpt = tenantWebhookRepository
.findByTenantIdAndCodeAndStatus(tenantId, MY_WEBHOOK_CODE, TenantWebhookStatus.ACTIVE);

if (webhookOpt.isEmpty()) {
log.warn("Webhook config not found for tenantId: {}, code: {}", tenantId, MY_WEBHOOK_CODE);
return;
}

TenantWebhook webhookConfig = webhookOpt.get();

// 2. Lấy auth configs
List<TenantAuthConfig> authConfigs = new ArrayList<>();
if (webhookConfig.getTenantAuthConfigIds() != null) {
try {
List<Long> authConfigIds = MapperUtils.readValue(
webhookConfig.getTenantAuthConfigIds(),
new TypeReference<List<Long>>() {}
);
if (authConfigIds != null && !authConfigIds.isEmpty()) {
authConfigs = tenantAuthConfigRepository
.findAllByTenantIdAndIdIn(tenantId, authConfigIds);
}
} catch (Exception e) {
authConfigs = new ArrayList<>();
}
}

// 3. Gửi webhook
webhookService.sendWebhook(tenantId, payload, webhookConfig, authConfigs);
}
}

4. Payload mẫu​

Payload được gửi dưới dạng JSON:

{
"user_001": [
{
"ticker": "VNM",
"type": "BUY",
"volume": 100,
"date": "2024-03-28",
"createdDate": "2024-03-28T10:00:00"
},
{
"ticker": "FPT",
"type": "SELL",
"volume": 50,
"date": "2024-03-28",
"createdDate": "2024-03-28T10:05:00"
}
],
"user_002": [
{
"ticker": "HPG",
"type": "BUY",
"volume": 200,
"date": "2024-03-28",
"createdDate": "2024-03-28T10:10:00"
}
]
}

Lưu ý: Payload hiện tại dùng Map<String, List<SignalDataDto>>. Nếu cần gửi loại dữ liệu khác, có thể thay đổi kiểu payload tương ứng.