Help me een aangepaste webhook-implementatie opzetten voor gebeurtenisgestuurde architectuur.
description
Door deze prompt te gebruiken, kun je een meer responsieve applicatie creëren die reageert op specifieke gebeurtenissen, wat de gebruikerservaring en systeem efficiëntie verbetert.
prompt
try_prompt
Ik wil een webhook-implementatie maken die specifieke acties triggert op basis van aangepaste gebeurtenissen in mijn applicatie. Mijn webhook-URL is: {{webhook_url}}. Beschrijf hoe je aangepaste gebeurtenistypen definieert, paylo ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Het opzetten van een webhook-implementatie voor aangepaste gebeurtenissen vereist een gestructureerde aanpak. Hier is een stapsgewijze gids met best practices:
1. Definieer Aangepaste Gebeurtenistypen
- Gebeurtenisnaam: Kies duidelijke, beschrijvende namen, bijvoorbeeld `nieuw_bericht`, `gebruikers_actie`, `betaling_voltooid`.
- Eventuele subtypes: Als nodig, voeg subcategorieën toe, zoals `betaling_voltooid/visa`.
- Documentatie: Documenteer alle eventtypen en hun betekenis.
2. Configureer Payload-structuren
- Consistentie: Gebruik een vaste structuur voor alle payloads, bijvoorbeeld:
```json
{
"event_type": "nieuw_bericht",
"timestamp": "2024-04-27T12:34:56Z",
"data": { ... }
}
```
- Data-inhoud: Plaats relevante gegevens onder `data`, zoals bericht-id, gebruiker-id, etc.
- Versiebeheer: Voeg een versieveld toe om structuurwijzigingen te beheren:
```json
{
"version": "1.0",
...
}
```
- Validatie: Gebruik JSON-schema’s om payloads te valideren.
3. Routing en Eventhandlers Opzetten
- Endpoint: Gebruik je webhook-URL: `https://mijnapp.com/webhooks`.
- Event-dispatching: Implementeer een router op je server die binnenkomende POST-verzoeken leest en het `event_type` gebruikt om de juiste handler aan te roepen.
- Handlerfuncties: Definieer aparte functies voor elke gebeurtenistype, bv. `handleNieuwBericht()`, `handleGebruikersActie()`.
- Asynchroon: Verwerk gebeurtenissen indien mogelijk asynchroon om latency te minimaliseren.
4. Best Practices voor Betrouwbaarheid en Conflicthantering
- Bevestiging: Stuur een 200 OK terug zodra de webhook is ontvangen en geaccepteerd.
- Retry-mechanismen: Bij niet-geslaagde verwerking, implementeer retries met exponential backoff.
- Idempotentie: Zorg dat dezelfde gebeurtenis meerdere keren verwerken geen problemen veroorzaakt, bijvoorbeeld door een uniek gebeurtenis-ID te gebruiken en bij te houden.
- Verificatie: Controleer de authenticiteit van verzoeken, bijvoorbeeld via geheime tokens of HMAC-siganturen.
- Loggen: Log alle ontvangen gebeurtenissen en verwerkingstatus voor audit en debugging.
- Conflictbeheer: Bij conflicten (bijvoorbeeld dubbele gebeurtenissen) gebruik idempotentie om consistentie te bewaren.
Door deze stappen te volgen, creëer je een robuuste, schaalbare webhook-implementatie die nauwkeurig reageert op je aangepaste gebeurtenissen en mogelijke problemen correct afhandelt.
provider: deepseek
model: deepseek-chat
Hier is een uitgebreide beschrijving voor het implementeren van uw webhook-systeem:
## 1. Aangepaste Gebeurtenistypen Definiëren
```json
{
"event_types": {
"user_registered": {
"description": "Nieuwe gebruiker geregistreerd",
"version": "1.0"
},
"order_created": {
"description": "Nieuwe bestelling geplaatst",
"version": "1.0"
},
"payment_processed": {
"description": "Betaling verwerkt",
"version": "1.0"
},
"subscription_cancelled": {
"description": "Abonnement geannuleerd",
"version": "1.0"
}
}
}
```
## 2. Payload-structuur Configureren
**Basis payload-structuur:**
```json
{
"event_id": "evt_123456789",
"event_type": "order_created",
"event_version": "1.0",
"timestamp": "2024-01-15T10:30:00Z",
"source": "https://uwapp.com/api",
"data": {
"order_id": "ord_987654321",
"customer_email": "klant@voorbeeld.nl",
"amount": 99.99,
"currency": "EUR"
},
"metadata": {
"attempt": 1,
"webhook_id": "wh_123456"
}
}
```
## 3. Routing voor Gebeurtenisafhandelaars
**Express.js voorbeeld:**
```javascript
const webhookRouter = express.Router();
// Event handler mapping
const eventHandlers = {
'user_registered': require('./handlers/userHandler'),
'order_created': require('./handlers/orderHandler'),
'payment_processed': require('./handlers/paymentHandler'),
'subscription_cancelled': require('./handlers/subscriptionHandler')
};
webhookRouter.post('/webhooks', async (req, res) => {
const { event_type, event_id } = req.body;
// Controleer dubbele events
if (await isDuplicateEvent(event_id)) {
return res.status(200).json({ status: 'duplicate_ignored' });
}
const handler = eventHandlers[event_type];
if (handler) {
try {
await handler.process(req.body);
res.status(200).json({ status: 'success' });
} catch (error) {
await logFailedEvent(event_id, error);
res.status(500).json({ status: 'error' });
}
} else {
res.status(400).json({ error: 'unknown_event_type' });
}
});
```
## 4. Best Practices voor Nauwkeurige Levering
### **Idempotentie Garanderen**
```javascript
class EventProcessor {
constructor() {
this.processedEvents = new Set();
}
async processEvent(event) {
// Controleer op duplicaten
if (this.processedEvents.has(event.event_id)) {
return { status: 'already_processed' };
}
// Idempotente verwerking
const result = await this.handleEventSafely(event);
// Markeer als verwerkt
this.processedEvents.add(event.event_id);
return result;
}
async handleEventSafely(event) {
// Implementeer idempotente logica
switch (event.event_type) {
case 'order_created':
return await this.createOrderIfNotExists(event.data);
case 'payment_processed':
return await this.updatePaymentStatus(event.data);
}
}
}
```
### **Retry Mechanisme**
```javascript
class WebhookDelivery {
async deliverWithRetry(webhookUrl, payload, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const response = await fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Signature': this.generateSignature(payload)
},
body: JSON.stringify(payload)
});
if (response.ok) return true;
// Exponential backoff
await this.sleep(Math.pow(2, attempt) * 1000);
} catch (error) {
console.error(`Attempt ${attempt} failed:`, error);
}
}
return false;
}
}
```
## 5. Conflictbeheer tussen Gebeurtenissen
### **Event Sourcing Pattern**
```javascript
class EventStore {
constructor() {
this.eventLog = [];
this.entityVersions = new Map();
}
async appendEvent(event) {
const entityId = event.data.entity_id;
const currentVersion = this.entityVersions.get(entityId) || 0;
// Optimistische locking
if (event.expected_version && event.expected_version !== currentVersion) {
throw new Error('Concurrent modification detected');
}
event.version = currentVersion + 1;
this.eventLog.push(event);
this.entityVersions.set(entityId, event.version);
return event;
}
async getEntityState(entityId) {
const events = this.eventLog.filter(e => e.data.entity_id === entityId);
return events.reduce((state, event) => this.applyEvent(state, event), {});
}
}
```
### **Event Sortering en Volgorde**
```javascript
class EventSequencer {
constructor() {
this.sequenceNumbers = new Map();
}
ensureOrderedProcessing(events) {
return events.sort((a, b) => {
// Sorteer op timestamp en sequence number
const timeDiff = new Date(a.timestamp) - new Date(b.timestamp);
if (timeDiff !== 0) return timeDiff;
return (a.sequence_number || 0) - (b.sequence_number || 0);
});
}
async processInOrder(entityId, events) {
const sortedEvents = this.ensureOrderedProcessing(events);
for (const event of sortedEvents) {
await this.processEventWithLock(entityId, event);
}
}
}
```
## 6. Beveiliging en Validatie
### **Webhook Signature**
```javascript
const crypto = require('crypto');
class WebhookSecurity {
generateSignature(payload, secret) {
return crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
}
verifySignature(signature, payload, secret) {
const expectedSignature = this.generateSignature(payload, secret);
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
}
```
### **Rate Limiting**
```javascript
const rateLimit = require('express-rate-limit');
const webhookLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minuut
max: 100, // maximaal 100 requests per minuut
message: {
error: 'Te veel webhook requests',
retry_after: 60
}
});
```
## 7. Monitoring en Logging
```javascript
class WebhookMonitor {
async logWebhookDelivery(event) {
await db.webhook_logs.insert({
event_id: event.event_id,
event_type: event.event_type,
delivery_status: 'pending',
attempt_count: 0,
last_attempt: null,
created_at: new Date()
});
}
async updateDeliveryStatus(eventId, status, error = null) {
await db.webhook_logs.update({
delivery_status: status,
last_attempt: new Date(),
error_message: error?.message,
attempt_count: db.raw('attempt_count + 1')
}).where({ event_id: eventId });
}
}
```
Deze implementatie biedt een robuuste basis voor uw webhook-systeem met aandacht voor betrouwbaarheid, beveiliging en schaalbaarheid.

