Ontwerp een REST API met het Idempotentie Design Pattern
description
Met deze prompt leer je hoe je je REST API robuuster maakt tegen dubbele verzoeken die anders tot fouten of inconsistente data kunnen leiden. Het toepassen van idempotentie verhoogt de betrouwbaarheid en gebruikerservaring, vooral bij netwerkproblemen of client retries. Dit is een belangrijke aanvulling op bestaande design patterns en lost specifieke problemen op die niet met andere patronen worden behandeld.
prompt
try_prompt
Help me een REST API te ontwerpen die het Idempotentie Design Pattern toepast om ervoor te zorgen dat herhaalde verzoeken dezelfde uitkomst hebben zonder ongewenste bijwerkingen. Mijn API-doel: <beschrijf het doel van ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht van hoe je een REST API kunt ontwerpen die het Idempotentie Design Pattern toepast voor het plaatsen en beheren van online bestellingen:
1. Doel van idempotentie in jouw API:
- Voorkomen dat herhaalde verzoeken (bijvoorbeeld door netwerkproblemen of gebruikersfouten) leiden tot dubbele bestellingen of ongewenste bijwerkingen.
- Zorgen voor consistente resultaten bij meerdere identieke verzoeken.
2. Structuur van de API-endpoints:
- **Maak- of Plaatsbestelling (POST /bestellingen):**
- Deze endpoint gebruikt een idempotentie-token dat door de client wordt meegegeven.
- Bij ontvangst van een verzoek met hetzelfde token wordt dezelfde bestelling geretourneerd of het verzoek genegeerd als het al verwerkt is.
- **Bekijk Bestelling (GET /bestellingen/{id}):**
- Geeft de status en details van een bestelling.
- **Annuleer Bestelling (DELETE /bestellingen/{id}):**
- Kan geconfigureerd worden voor idempotent gedrag: meerdere keren proberen te annuleren heeft hetzelfde effect.
- **Update Bestelling (PUT /bestellingen/{id}):**
- Voor volledige vervanging; kan ook idempotent zijn.
3. HTTP-methoden en idempotentie:
- **POST**: normaal niet idempotent, maar door gebruik van idempotentie tokens kan het dat wel worden.
- **PUT**: intrinsiek idempotent, geschikt voor het bijwerken of aanmaken van resources.
- **DELETE**: meestal idempotent.
- **GET**: idempotent (geen bijwerkingen).
4. Implementatie van idempotentie mechanismen:
- **Idempotentie Token (Idempotency-Key):**
- Client stuurt een unieke token (bijvoorbeeld UUID) mee in de header of body bij het plaatsen van een bestelling, bijvoorbeeld in de header `Idempotency-Key`.
- Server bewaart de verwerkingstatus van dat token (bijvoorbeeld in een cache of database).
- Bij herhaald verzoek met dezelfde token:
- Als de bestelling al succesvol is verwerkt, retourneert server de bestaande bestelling of bevestiging.
- Als het proces nog niet is voltooid, kan de server wachten of hetzelfde antwoord teruggeven.
- **Persistente opslag:**
- Bewaar de associatie tussen het idempotentie-token en de gegenereerde resource (bestelling) samen met de status.
- **Tijdslimiet:**
- Bepaal hoe lang de server het token en de status ervan bewaart (bijvoorbeeld 24 uur of 7 dagen).
- **Beveiliging en validatie:**
- Zorg dat tokens uniek en moeilijk te raden zijn.
- Controleer op dubbele tokens om herhaalde bestellingen te voorkomen.
5. Voorbeeld flow:
- Client stuurt POST /bestellingen met body en header `Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000`.
- Server checkt of deze sleutel al bestaat:
- Ja: retourneert de bestaande bestelling of bevestiging.
- Nee: verwerkt de bestelling, slaat de status op onder die sleutel, en retourneert de bevestiging.
- Bij een herhaalverzoek met dezelfde sleutel wordt hetzelfde resultaat teruggegeven zonder een nieuwe bestelling te plaatsen.
**Samenvatting:**
- Gebruik **POST** voor het plaatsen van bestellingen, aangevuld met een **Idempotency-Key** header.
- Bewaar de status van de bestelling en de token in een datastore.
- Bij herhaalde verzoeken met dezelfde key, retourneer de bestaande resource of bevestiging.
- Maak gebruik van **PUT** en **DELETE** waar passend, omdat deze intrinsiek idempotent zijn.
Hierdoor wordt je API robuust, betrouwbaar en veilig tegen dubbele bestellingen door herhaalde verzoeken.
provider: deepseek
model: deepseek-chat
Zeker, hier is een gedetailleerd ontwerp voor een idempotente REST API voor online bestellingen, volledig in het Nederlands:
### 1. Basisprincipes van Idempotentie
Idempotentie garandeert dat meerdere identieke verzoeken hetzelfde resultaat hebben als één verzoek. Dit is cruciaal bij:
- Netwerkfouten waarbij clients verzoeken opnieuw versturen
- Gebruikers die per ongeluk formulieren opnieuw indienen
- Geautomatiseerde systemen die failed requests retryen
### 2. Geschikte HTTP-methoden voor Idempotentie
- **POST**: Standaard niet idempotent - vereist speciale implementatie
- **PUT**: Van nature idempotent - ideaal voor updates
- **GET**: Veilig en idempotent
- **DELETE**: Idempotent (verwijderen van reeds verwijderde resource geeftzelfde resultaat)
- **PATCH**: Kan idempotent gemaakt worden met zorgvuldige implementatie
### 3. Idempotentie Token Implementatie
#### A. Token Generatie
```typescript
// Client-side token generatie
const idempotencyToken = generateUUID();
// Voorbeeld: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
```
#### B. Request Headers
```http
POST /api/orders
Content-Type: application/json
Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Authorization: Bearer <jwt-token>
{
"productId": "prod_123",
"quantity": 2,
"shippingAddress": {...}
}
```
### 4. Server-side Implementatie
#### A. Database Schema
```sql
CREATE TABLE idempotency_store (
idempotency_key VARCHAR(255) PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
http_method VARCHAR(10) NOT NULL,
route_path VARCHAR(255) NOT NULL,
request_hash TEXT NOT NULL,
response_code INT NOT NULL,
response_body JSONB,
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP NOT NULL
);
CREATE INDEX idx_idempotency_user ON idempotency_store(user_id);
CREATE INDEX idx_idempotency_expires ON idempotency_store(expires_at);
```
#### B. Verwerkingslogica
```python
async def create_order(request: OrderRequest, idempotency_key: str):
# Stap 1: Validatie
if not idempotency_key:
return HTTP_400_BAD_REQUEST
# Stap 2: Check bestaande response
cached_response = await idempotency_store.get(idempotency_key)
if cached_response:
return Response(
status=cached_response.response_code,
body=cached_response.response_body
)
# Stap 3: Request hash voor duplicate detection
request_hash = generate_request_hash(request)
existing_hash = await find_existing_hash(request_hash)
if existing_hash:
return HTTP_409_CONFLICT # Duplicate request detected
# Stap 4: Transactie starten
async with database.transaction():
# Lock mechanisme voor race conditions
locked_key = await idempotency_store.lock(idempotency_key)
try:
# Stap 5: Order verwerking
order = await process_order_creation(request)
# Stap 6: Response opslaan
await idempotency_store.save(
key=idempotency_key,
response_code=201,
response_body=order.to_dict()
)
return Response(status=201, body=order.to_dict())
except DuplicateOrderError:
return HTTP_409_CONFLICT
finally:
await idempotency_store.unlock(locked_key)
```
### 5. Endpoint Specificaties
#### A. Order Aanmaken (POST /api/orders)
```http
POST /api/orders
Headers:
Idempotency-Key: <uuid>
Authorization: Bearer <token>
Response:
- 201 Created: Order succesvol aangemaakt
- 200 OK: Bestaande order gevonden (bij herhaald verzoek)
- 409 Conflict: Duplicate request gedetecteerd
- 422 Unprocessable Entity: Validatiefouten
```
#### B. Order Bijwerken (PUT /api/orders/{id})
```http
PUT /api/orders/ord_123
Headers:
Idempotency-Key: <uuid>
Body:
{
"status": "verzonden",
"trackingNumber": "TRK789"
}
Response:
- 200 OK: Update succesvol
- 404 Not Found: Order niet gevonden
```
#### C. Order Annuleren (DELETE /api/orders/{id})
```http
DELETE /api/orders/ord_123
Headers:
Idempotency-Key: <uuid>
Response:
- 204 No Content: Order geannuleerd
- 404 Not Found: Order niet gevonden (idempotent)
```
### 6. Beveiligingsmaatregelen
#### A. Token Beperkingen
- **Geldigheidsduur**: 24 uur
- **Gebruikerscoping**: Tokens zijn gebruiker-specifiek
- **Request binding**: Token gebonden aan specifieke resource + actie
#### B. Rate Limiting
```typescript
const rateLimitConfig = {
windowMs: 15 * 60 * 1000, // 15 minuten
max: 100, // maximaal 100 requests per window
message: "Te veel idempotente verzoeken"
};
```
### 7. Foutafhandeling
#### A. Client Errors
```json
{
"error": {
"code": "IDEMPOTENCY_KEY_REQUIRED",
"message": "Idempotency-Key header is verplicht voor deze actie",
"details": {
"required_header": "Idempotency-Key",
"format": "UUID v4"
}
}
}
```
#### B. Server Errors
- **500 Internal Server Error**: Bij onverwachte fouten
- **503 Service Unavailable**: Bij onderhoud of overload
### 8. Best Practices
#### A. Token Management
- Genereer tokens aan client-side
- Gebruik cryptografisch secure random generators
- Sla tokens niet permanent op aan client-side
#### B. Response Caching
- Cache responses maximaal 24 uur
- Invalideer cache bij wijzigingen in onderliggende data
- Gebruik appropriate HTTP caching headers
#### C. Monitoring en Logging
```typescript
const monitoringMetrics = {
idempotency_usage: "aantal idempotente verzoeken",
duplicate_detection: "aantal gedupliceerde verzoeken",
token_reuse: "aantal hergebruikte tokens"
};
```
### 9. Client Implementatie Voorbeeld
```javascript
class OrderAPI {
constructor() {
this.idempotencyKeys = new Map();
}
async createOrder(orderData) {
const idempotencyKey = this.getOrCreateIdempotencyKey('create_order', orderData);
try {
const response = await fetch('/api/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
'Authorization': `Bearer ${this.authToken}`
},
body: JSON.stringify(orderData)
});
return await this.handleResponse(response);
} catch (error) {
throw new Error(`Order creatie mislukt: ${error.message}`);
}
}
getOrCreateIdempotencyKey(operation, data) {
const key = `${operation}_${JSON.stringify(data)}`;
if (!this.idempotencyKeys.has(key)) {
this.idempotencyKeys.set(key, generateUUID());
}
return this.idempotencyKeys.get(key);
}
}
```
Dit ontwerp zorgt voor robuuste idempotentie terwijl het de API gebruiksvriendelijk en veilig houdt. De implementatie voorkomt duplicate orders, handhaaft consistentie en biedt uitstekende foutafhandeling.

