Idempotentność
Wywołania sieciowe kończą się niepowodzeniem w niejednoznaczny sposób: żądanie przekracza limit czasu, ale czy dokument został utworzony? Klucze idempotentności pozwalają bezpiecznie ponawiać modyfikujące żądania bez tworzenia duplikatów.
Jak to działa
W żądaniach POST tworzących zasoby należy przesłać nagłówek Idempotency-Key (unikalną wartość dla każdej logicznej operacji, idealny jest UUID v4):
Idempotency-Key: 7c1f1d6e-0b2a-4a1e-9b1a-2a4e9b1a2a4e
- Pierwsze żądanie z danym kluczem jest wykonywane normalnie, a jego wynik zostaje zapamiętany.
- Każde ponowienie z tym samym kluczem zwraca pierwotny wynik, zamiast tworzyć drugi dokument.
- Klucze są przechowywane przez 24 godziny.
Należy wygenerować jeden klucz na intencję (np. „utworzenie faktury dla zamówienia #1234") i używać go we wszystkich ponowieniach tej intencji, nie zaś w różnych operacjach.
import { randomUUID } from 'node:crypto';
const key = randomUUID();
async function createInvoiceWithRetry(payload: unknown) {
for (let attempt = 0; attempt < 3; attempt++) {
const res = await fetch('https://prod.api.fakturnia.pl/external/v1/documents', {
method: 'POST',
headers: {
'Authorization': `Bearer ${await getToken()}`,
'Content-Type': 'application/json',
'Idempotency-Key': key, // same key on every retry
},
body: JSON.stringify(payload),
});
if (res.status < 500 && res.status !== 429) return res.json();
await new Promise(r => setTimeout(r, 2 ** attempt * 500)); // backoff
}
throw new Error('exhausted retries');
}
Klucze idempotentności należy łączyć z mechanizmem backoff. Ponawianie odpowiedzi
5xx/429jest bezpieczne tylko wtedy, gdy ten sam klucz gwarantuje, że operacja zostanie wykonana co najwyżej raz.
Tworzenie dokumentów to główny idempotentny punkt końcowy. Operacje odczytu są z natury idempotentne i nie wymagają klucza.