Ontwerp een REST API met het State Machine Design Pattern voor Workflowbeheer
description
Helpt gebruikers bij het ontwerpen van API's die complexe workflows beheren met duidelijke statusbeheer, waardoor fouten door ongeldige overgangen worden verminderd en de onderhoudbaarheid verbetert. Biedt praktische richtlijnen voor het modelleren van statussen en overgangen, essentieel voor API's die processen zoals orderbeheer, ticketing of goedkeuringssystemen afhandelen.
prompt
Help mij een REST API te ontwerpen die het State Machine Design Pattern toepast om workflows te beheren met gedefinieerde statussen en overgangen. Mijn API doel: <voer het doel van je API in>. Beschrijf hoe ik de statussen, overgangen en ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Hier is een uitgebreide beschrijving van het ontwerpen van een REST API voor orderverwerking gebaseerd op het State Machine Design Pattern, inclusief modellen, endpoints, request- en response-formaten, en best practices:
1. Modellering van Statussen, Overgangen en Acties
a. States (Statussen):
Definieer een enumeratie van mogelijke statussen:
- in_afwachting
- goedgekeurd
- verzonden
- geleverd
b. Overgangen:
Beperk overgangen volgens logica, bijvoorbeeld:
- in_afwachting → goedgekeurd
- goedgekeurd → verzonden
- verzonden → geleverd
c. Acties:
Bij elke overgang kunnen acties horen, zoals:
- goedkeuren order
- verzenden order
- bevestigen levering
2. Endpoints en Functionaliteiten
a. Orders Resources
- GET /orders/{orderId}
Haalt de details van een order op, inclusief status en geschiedenis.
- POST /orders
Creëert een nieuwe order in de initiële status ('in_afwachting').
- PATCH /orders/{orderId}/status
Wijzigt de status van een order, mits de overgang geldig is.
- GET /orders/{orderId}/history
Opvragen van de transactiegeschiedenis van statuswijzigingen.
b. Voorbeeld Endpoint-structuur
```plaintext
GET /orders/{orderId}
POST /orders
PATCH /orders/{orderId}/status
GET /orders/{orderId}/history
```
3. Request- en Response-Format
a. Nieuwe order aanmaken (POST /orders)
Request:
```json
{
"klantId": "K12345",
"producten": [
{"productId": "P001", "aantal": 2},
{"productId": "P002", "aantal": 1}
]
}
```
Response:
```json
{
"orderId": "O123456",
"status": "in_afwachting",
"aangemaaktOp": "2023-10-23T14:55:00Z",
"statusGeschiedenis": [
{
"status": "in_afwachting",
"timestamp": "2023-10-23T14:55:00Z",
"actie": "Order aangemaakt"
}
]
}
```
b. Statuswijziging (PATCH /orders/{orderId}/status)
Request:
```json
{
"nieuwStatus": "goedgekeurd"
}
```
Response:
```json
{
"orderId": "O123456",
"oudestatus": "in_afwachting",
"nieuwestatus": "goedgekeurd",
"timestamp": "2023-10-23T15:00:00Z",
"message": "Status succesvol gewijzigd"
}
```
4. Validatie en Afhandeling van Ongeldige Overgangen
- Controleer of de gevraagde overgang geldig is volgens het state machine model.
- Bij ongeldige overgang:
```json
{
"error": "Ongeldige statuswijziging",
"huidigeStatus": "in_afwachting",
"proposedStatus": "verzonden",
"beschrijving": "Deze overgang is niet toegestaan zonder goedkeuring."
}
```
- API moet een passende HTTP-statuscode geven, bijvoorbeeld 400 Bad Request.
5. Best Practices voor Consistentie en Traceerbaarheid
- Gebruik duidelijke en consistente status- en actie-velden.
- Log elke statuswijziging met timestamp, oude en nieuwe status, en actie.
- Voeg een 'statusGeschiedenis' toe aan elke order voor audit-doeleinden.
- Maak gebruik van idempotente bewerkingen waar mogelijk (bijvoorbeeld bij statuswijzigingen).
- Documenteer alle mogelijke statussen en overgangen in de API-documentatie.
- Overweeg het gebruik van HATEOAS om clients te begeleiden bij beschikbare acties afhankelijk van de huidige status.
6. Samenvatting van het State Machine Model
- States:
- in_afwachting
- goedgekeurd
- verzonden
- geleverd
- Valid Overgangen:
- in_afwachting → goedgekeurd
- goedgekeurd → verzonden
- verzonden → geleverd
- Acties kunnen worden getriggerd afhankelijk van de status.
Met dit ontwerp kan je workflowbeheer helder, traceerbaar en robuust worden ingericht conform het State Machine Pattern binnen een REST API.
provider: deepseek
model: deepseek-chat
Zeker! Ik help je bij het ontwerpen van een REST API voor orderverwerking met het State Machine Pattern. Hier is een complete uitwerking:
## 1. Status en Overgangen Model
### Statussen
```json
{
"statuses": ["PENDING", "APPROVED", "SHIPPED", "DELIVERED", "CANCELLED"]
}
```
### Toegestane overgangen
```json
{
"transitions": {
"PENDING": ["APPROVED", "CANCELLED"],
"APPROVED": ["SHIPPED", "CANCELLED"],
"SHIPPED": ["DELIVERED"],
"DELIVERED": [],
"CANCELLED": []
}
}
```
## 2. Database Model
```sql
-- Orders tabel
CREATE TABLE orders (
id UUID PRIMARY KEY,
customer_id UUID NOT NULL,
total_amount DECIMAL(10,2),
current_status VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Status geschiedenis tabel
CREATE TABLE order_status_history (
id UUID PRIMARY KEY,
order_id UUID REFERENCES orders(id),
from_status VARCHAR(50),
to_status VARCHAR(50) NOT NULL,
transition_reason TEXT,
performed_by UUID,
created_at TIMESTAMP DEFAULT NOW()
);
```
## 3. API Endpoints
### 3.1 Order aanmaken
**POST** `/api/orders`
```json
{
"customer_id": "123e4567-e89b-12d3-a456-426614174000",
"items": [
{"product_id": "prod-001", "quantity": 2, "price": 25.50}
],
"total_amount": 51.00
}
```
**Response:**
```json
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"customer_id": "123e4567-e89b-12d3-a456-426614174000",
"current_status": "PENDING",
"total_amount": 51.00,
"created_at": "2024-01-15T10:30:00Z",
"status_history": []
}
```
### 3.2 Status overgang uitvoeren
**POST** `/api/orders/{orderId}/transitions`
```json
{
"target_status": "APPROVED",
"reason": "Betaling ontvangen",
"performed_by": "user-123"
}
```
**Response:**
```json
{
"order_id": "123e4567-e89b-12d3-a456-426614174000",
"previous_status": "PENDING",
"new_status": "APPROVED",
"transition_time": "2024-01-15T11:00:00Z",
"transition_id": "transition-001"
}
```
### 3.3 Order details ophalen
**GET** `/api/orders/{orderId}`
```json
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"customer_id": "123e4567-e89b-12d3-a456-426614174000",
"current_status": "APPROVED",
"total_amount": 51.00,
"created_at": "2024-01-15T10:30:00Z",
"status_history": [
{
"from_status": null,
"to_status": "PENDING",
"transition_time": "2024-01-15T10:30:00Z",
"reason": "Order aangemaakt"
},
{
"from_status": "PENDING",
"to_status": "APPROVED",
"transition_time": "2024-01-15T11:00:00Z",
"reason": "Betaling ontvangen"
}
]
}
```
### 3.4 Beschikbare overgangen ophalen
**GET** `/api/orders/{orderId}/available-transitions`
```json
{
"current_status": "APPROVED",
"available_transitions": ["SHIPPED", "CANCELLED"]
}
```
## 4. State Machine Implementatie
### State Machine Klasse
```python
class OrderStateMachine:
def __init__(self):
self.transitions = {
'PENDING': ['APPROVED', 'CANCELLED'],
'APPROVED': ['SHIPPED', 'CANCELLED'],
'SHIPPED': ['DELIVERED'],
'DELIVERED': [],
'CANCELLED': []
}
def can_transition(self, from_status, to_status):
return to_status in self.transitions.get(from_status, [])
def get_available_transitions(self, current_status):
return self.transitions.get(current_status, [])
```
### Service Laag
```python
class OrderService:
def __init__(self):
self.state_machine = OrderStateMachine()
def transition_order(self, order_id, target_status, reason, user_id):
order = self.get_order(order_id)
if not self.state_machine.can_transition(order.current_status, target_status):
raise InvalidTransitionError(
f"Ongeldige overgang van {order.current_status} naar {target_status}"
)
# Update order status
previous_status = order.current_status
order.current_status = target_status
order.updated_at = datetime.utcnow()
# Log status wijziging
self.log_status_transition(
order_id, previous_status, target_status, reason, user_id
)
return order
```
## 5. Foutafhandeling
### Custom Exceptions
```python
class InvalidTransitionError(Exception):
pass
class OrderNotFoundError(Exception):
pass
```
### Error Response
```json
{
"error": "INVALID_TRANSITION",
"message": "Ongeldige overgang van PENDING naar DELIVERED",
"current_status": "PENDING",
"available_transitions": ["APPROVED", "CANCELLED"],
"timestamp": "2024-01-15T11:00:00Z"
}
```
## 6. Best Practices
### 6.1 Consistentie en ACID
- Gebruik database transacties voor status updates
- Implementeer optimistic locking met `version` veld
- Valideer business rules voor elke overgang
### 6.2 Traceerbaarheid
- Log alle status wijzigingen met reden en gebruiker
- Implementeer audit logging
- Bewaar complete status geschiedenis
### 6.3 Idempotentie
```python
# Idempotente status overgang
def transition_order(order_id, target_status, idempotency_key):
if self.is_transition_processed(idempotency_key):
return self.get_existing_transition(idempotency_key)
# Verwerk overgang
return self.process_transition(order_id, target_status, idempotency_key)
```
### 6.4 CQRS Pattern
- Scheid read en write operations
- Gebruik materialized views voor status rapportages
- Cache veelgebruikte queries
## 7. Event-Driven Architecture
### Status Change Events
```json
{
"event_type": "ORDER_STATUS_CHANGED",
"order_id": "123e4567-e89b-12d3-a456-426614174000",
"previous_status": "PENDING",
"new_status": "APPROVED",
"timestamp": "2024-01-15T11:00:00Z",
"metadata": {
"reason": "Betaling ontvangen",
"user_id": "user-123"
}
}
```
## 8. Security Considerations
- Authenticatie en autorisatie voor status wijzigingen
- Role-based access control voor verschillende overgangen
- Rate limiting op status update endpoints
- Input validatie en sanitization
Deze architectuur biedt een robuuste foundation voor orderverwerking met duidelijke status overgangen, volledige traceerbaarheid en goede foutafhandeling.