Concepten
Idempotentie
Stuur een Idempotency-Key mee met een POST, dan krijgt een herhaling na een verbroken verbinding het eerste antwoord, in plaats van dat iemand twee keer wordt geregistreerd.
Waarom
Een verbinding kan wegvallen nadat AttendBeacon iemand heeft geregistreerd, maar voordat je code dat heeft gehoord. Stuur je dezelfde POST opnieuw, dan zou er een tweede ticket worden uitgegeven. Met een Idempotency-Key gebeurt dat niet: het tweede verzoek krijgt het antwoord van het eerste.
Hoe
Maak voor elk verzoek een eigen sleutel (een UUID is ideaal) en stuur die mee met de POST. Bewaar hem bij het verzoek tot je een antwoord hebt, en stuur bij elke herhaling dezelfde sleutel mee.
curl -X POST "https://attendbeacon.com/api/v1/events/b3ac0000-0000-4000-8000-000000000001/registrations" \
-H "Authorization: Bearer $ATTENDBEACON_KEY" \
-H "Idempotency-Key: 6f1c2a9e-4b7d-4c0f-8e3a-5b9d1c7e0f42" \
-H "Content-Type: application/json" \
-d '{ "ticketTypeId": "b3ac0006-0000-4000-8000-000000000001", "firstName": "Anna", "lastName": "de Vries", "email": "anna.devries@example.com" }'const idempotencyKey = crypto.randomUUID(); // once per registration, kept for its retries
async function register(person) {
for (let attempt = 1; ; attempt++) {
try {
const response = await fetch(`${base}/events/${eventId}/registrations`, {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Idempotency-Key": idempotencyKey, "Content-Type": "application/json" },
body: JSON.stringify(person)
});
if (response.status < 500) return response; // an answer: the first, or the first again
} catch { /* the connection dropped: try again with the same key */ }
if (attempt === 4) throw new Error("AttendBeacon did not answer.");
await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 1000));
}
}var idempotencyKey = Guid.NewGuid().ToString(); // once per registration, kept for its retries
for (var attempt = 1; ; attempt++)
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"events/{eventId}/registrations") { Content = JsonContent.Create(person) };
request.Headers.Add("Idempotency-Key", idempotencyKey);
try
{
using var response = await client.SendAsync(request);
if ((int)response.StatusCode < 500) return await response.Content.ReadFromJsonAsync<JsonElement>();
}
catch (HttpRequestException) { /* try again with the same key */ }
if (attempt == 4) throw new InvalidOperationException("AttendBeacon did not answer.");
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
}idempotency_key = str(uuid.uuid4()) # once per registration, kept for its retries
for attempt in range(1, 5):
try:
response = requests.post(
f"{base}/events/{event_id}/registrations",
headers={"Authorization": f"Bearer {key}", "Idempotency-Key": idempotency_key},
json=person,
timeout=30,
)
if response.status_code < 500:
break # an answer: the first, or the first again
except requests.ConnectionError:
pass # try again with the same key
time.sleep(2 ** attempt)$idempotencyKey = [guid]::NewGuid().ToString() # once per registration, kept for its retries
$headers["Idempotency-Key"] = $idempotencyKey
$body = $person | ConvertTo-Json
foreach ($attempt in 1..4) {
try {
$attendee = Invoke-RestMethod -Method Post -Uri "$base/events/$eventId/registrations" -Headers $headers -ContentType "application/json" -Body $body
break
} catch {
if ($_.Exception.Response -and [int]$_.Exception.Response.StatusCode -lt 500) { throw }
Start-Sleep -Seconds ([math]::Pow(2, $attempt))
}
}Wat er wordt bewaard, en hoe lang
Het eerste antwoord op een sleutel (de status, Location en de body) wordt 24 uur bewaard en opnieuw gegeven aan elk verzoek met dezelfde sleutel, methode, hetzelfde pad en dezelfde body. Een herhaald antwoord heeft Idempotent-Replayed: true.
| Situatie | Antwoord |
|---|---|
| Een herhaling van een verzoek dat al antwoord kreeg | Het eerste antwoord, met Idempotent-Replayed: true |
| Een herhaling terwijl het eerste nog wordt afgehandeld | 409 idempotencyKeyInUse, met Retry-After: 1 |
| Dezelfde sleutel met een andere methode, een ander pad of een andere body | 422 idempotencyKeyReused: gebruik een nieuwe sleutel voor een nieuw verzoek |
| Een sleutel langer dan 255 tekens, of met spaties | 400 invalidIdempotencyKey |
| Het eerste verzoek mislukte aan de kant van AttendBeacon (5xx) | Er wordt niets bewaard, dus de herhaling wordt opnieuw afgehandeld |
Een sleutel hoort bij de API-sleutel die hem verstuurde: twee integraties kunnen elkaar niet in de weg zitten. De bewaarde antwoorden kunnen een persoon noemen; als die persoon de eigen gegevens verwijdert, worden de antwoorden die hem of haar noemen ook verwijderd.
Welke aanroepen
Elke POST neemt een Idempotency-Key: registreren, tickets uitgeven, annuleren, inchecken, en evenementen, sessies, kortingscodes en webhooks maken. PATCH, PUT en DELETE kun je van nature veilig herhalen; PATCH neemt in plaats daarvan If-Match, zodat een tussentijdse wijziging niet wordt overschreven (Fouten, preconditionFailed).