Begrepp
Idempotens
Skicka en Idempotency-Key med en POST, så besvaras ett nytt försök efter en bruten anslutning med det första svaret i stället för att någon anmäls två gånger.
Varför
En anslutning kan brytas efter att AttendBeacon har anmält någon men innan din kod fick veta det. Skickas samma POST igen skulle den utfärda en andra biljett. Med en Idempotency-Key gör den inte det: det andra anropet får det förstas svar.
Hur
Skapa en egen idempotensnyckel för varje anrop (ett UUID är idealiskt) och skicka den med din POST. Behåll den tillsammans med anropet tills du har fått ett svar, och skicka samma nyckel vid varje nytt försök.
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))
}
}Vad som sparas, och hur länge
Det första svaret på en idempotensnyckel (dess status, Location och brödtext) sparas i 24 timmar och ges igen till varje anrop med samma nyckel, metod, sökväg och brödtext. Ett upprepat svar har med sig Idempotent-Replayed: true.
| Situation | Svar |
|---|---|
| Ett nytt försök med ett anrop som har besvarats | Det första svaret, med Idempotent-Replayed: true |
| Ett nytt försök medan det första fortfarande hanteras | 409 idempotencyKeyInUse, med Retry-After: 1 |
| Samma nyckel med en annan metod, sökväg eller brödtext | 422 idempotencyKeyReused: använd en ny nyckel för ett nytt anrop |
| En nyckel längre än 255 tecken, eller med mellanslag | 400 invalidIdempotencyKey |
| Det första anropet misslyckades hos AttendBeacon (5xx) | Inget sparas, så det nya försöket hanteras från början |
En idempotensnyckel hör till den API-nyckel som skickade den: två integrationer kan inte krocka. De sparade svaren kan namnge en person; när den personen raderar sina uppgifter raderas även de svar som namnger personen.
Vilka anrop
Varje POST tar en Idempotency-Key: anmäla, utfärda biljetter, avboka, checka in, skapa evenemang, sessioner, rabattkoder och webhooks. PATCH, PUT och DELETE kan till sin natur upprepas säkert; PATCH tar i stället If-Match, så att en ändring som gjorts under tiden inte skrivs över (Fel, preconditionFailed).