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ó webhookConfigauthConfigs, 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.