Veilige integratie van externe API's zodat je app blijft werken tijdens storingen. Leer over timeouts, retries, circuit breakers en snelle checks.

Een externe API kan op manieren falen die niet als een duidelijke "uitval" lijken. Het meest voorkomende probleem is traagheid: verzoeken blijven hangen, antwoorden komen te laat binnen en je app blijft wachten. Als die calls op het kritieke pad liggen, stapelt een klein probleem buiten jouw controle zich op binnen je systeem.
Zo verandert een lokale vertraging in een volledige outage. Threads of workers blijven hangen, wachtrijen groeien, database-transacties blijven langer open en nieuwe aanvragen beginnen te timen-outen. Binnen korte tijd voelen zelfs pagina's die de externe API niet gebruiken zich kapot omdat het systeem wordt overbelast door wachtend werk.
De impact is concreet. Een onbetrouwbare identity-provider blokkeert aanmeldingen en logins. Een payment-gateway-timeout bevriest de checkout, waardoor gebruikers niet zeker weten of ze zijn gefactureerd. Een vertraging in messaging stopt wachtwoordresets en orderbevestigingen, wat een tweede golf van retries en supporttickets veroorzaakt.
Het doel is simpel: isoleer externe fouten zodat kernworkflows blijven doorgaan. Dat kan betekenen dat je een gebruiker een bestelling laat plaatsen en de betaling later bevestigt, of dat je aanmelden toestaat ook als een welkomstmail faalt.
Een praktisch succescriterium: als een provider traag of down is, moet je app nog steeds snel en duidelijk reageren en moet de blast radius klein blijven. Bijvoorbeeld: de meeste kernrequests worden nog binnen je normale latentie afgesloten, fouten blijven beperkt tot features die echt van die API afhangen, gebruikers zien een duidelijke status (gequeued, in afwachting, probeer later opnieuw) en herstel gebeurt automatisch als de provider terug is.
De meeste fouten zijn voorspelbaar, ook al is het moment dat ze optreden dat niet. Benoem ze van tevoren en je kunt beslissen wat te herproberen, wat te stoppen en wat je aan de gebruiker laat zien.
Veelvoorkomende categorieën:
Niet alle fouten betekenen hetzelfde. Transient issues zijn het vaak waard om te herproberen omdat de volgende call kan slagen (netwerkflitsen, timeouts, 502/503 en sommige 429s na wachten). Permanente problemen lossen meestal niet vanzelf op (ongeldige credentials, verkeerde endpoints, fout geformatteerde requests, permissie-ontzeggingen).
Iedere fout gelijk behandelen verandert een klein incident in downtime. Herproberen van permanente fouten is tijdverspilling, raakt rate limits sneller en bouwt een backlog op die alles vertraagt. Nooit transient failures herproberen dwingt gebruikers acties te herhalen en laat werk vallen dat even later had kunnen slagen.
Besteed extra aandacht aan workflows waar een pauze als een breuk voelt: checkout, login, wachtwoordreset en notificaties (e-mail/SMS/push). Een piek van twee seconden in een marketing-API is vervelend. Een piek van twee seconden bij betalingsautorisatie blokkeert inkomsten.
Een nuttige test is: "Is deze call nu nodig om de hoofdtaak van de gebruiker af te ronden?" Zo ja, dan heb je strakke timeouts, zorgvuldige retries en een duidelijk faalpad nodig. Zo nee, verplaats het naar een queue en houd de app responsief.
Een timeout is de maximale tijd die je bereid bent te wachten voordat je stopt en doorgaat. Zonder een duidelijke grens kan één trage provider wachtende requests ophopen en belangrijk werk blokkeren.
Het helpt om twee soorten wachten te scheiden:
Getallen kiezen gaat niet om perfectie. Het gaat om matchen met menselijke geduld en je workflow.
Een praktische manier om timeouts te kiezen is terugwerken vanuit de ervaring:
De afweging is reëel. Te lang en je bindt threads, workers en databaseverbindingen. Te kort en je creëert valse fouten en triggert onnodige retries.
Retries helpen wanneer een fout waarschijnlijk tijdelijk is: een korte netwerkstoring, DNS-probleem of een eenmalige 500/502/503. In die gevallen kan een tweede poging slagen en merken gebruikers er niets van.
Het risico is een retry-storm. Als veel clients tegelijk falen en allemaal tegelijk opnieuw proberen, kunnen ze de provider (en je eigen workers) overbelasten. Backoff en jitter voorkomen dat.
Een retry-budget houdt je eerlijk. Houd pogingen laag en cap totale tijd zodat kernworkflows niet blijven hangen op iemand anders.
Herprobeer geen voorspelbare clientfouten zoals 400/422 validatieproblemen, 401/403 auth-fouten of 404s. Die zullen vrijwel altijd opnieuw falen en alleen maar extra load toevoegen.
Nog een vangrail: alleen writes (POST/PUT) herproberen als je idempotentie hebt, anders loop je het risico op dubbele kosten of dubbele records.
Idempotentie betekent dat je dezelfde request twee keer kunt uitvoeren en toch hetzelfde eindresultaat krijgt. Dat is belangrijk omdat retries normaal zijn: netwerken vallen weg, servers herstarten en clients timen-outen. Zonder idempotentie kan een "goedbedoelde" retry duplicaten en echte financiële problemen veroorzaken.
Stel je checkout voor: de payment-API is traag, je app timet out en je probeert opnieuw. Als de eerste call wel succesvol was, kan de retry een tweede afschrijving veroorzaken. Hetzelfde risico geldt voor acties als het aanmaken van een order, starten van een abonnement, het versturen van een e-mail/SMS, uitvoeren van een refund of het aanmaken van een supportticket.
De oplossing is om een idempotency-key (of request-ID) aan elke "doe iets" call toe te voegen. Die moet uniek zijn per gebruikersactie, niet per poging. De provider (of je eigen service) gebruikt die sleutel om duplicaten te detecteren en hetzelfde resultaat terug te geven in plaats van de actie opnieuw uit te voeren.
Behandel de idempotency-key als onderdeel van het datamodel, niet als een header waarvan je hoopt dat niemand hem vergeet.
Genereer één key wanneer de gebruiker de actie start (bijvoorbeeld wanneer ze op Betalen klikken) en sla die op bij je lokale record.
Bij elke poging:
Als jij de "provider" bent voor interne calls, dwing dan hetzelfde gedrag server-side af.
Een circuit breaker is een veiligheidschakelaar. Als een externe service begint te falen, stop je tijdelijk met het bellen ervan in plaats van nog meer requests op te stapelen die waarschijnlijk ook zullen timen-outen.
Circuit breakers hebben meestal drie staten:
Als de breaker open is, moet je app iets voorspelbaars doen. Als een adres-validatie-API down is tijdens aanmelding, accepteer het adres en markeer het voor latere controle. Als een payment risk check down is, zet dan de bestelling in een queue voor handmatige review of schakel die optie tijdelijk uit en leg dat uit.
Kies thresholds die bij de impact voor gebruikers passen:
Houd cooldowns kort (seconden tot een minuut) en beperk half-open probes. Het doel is eerst core workflows te beschermen en vervolgens snel te herstellen.
Als een externe API traag of down is, is je doel de gebruiker in beweging te houden. Dat betekent een plan B hebben dat eerlijk vertelt wat er gebeurde.
Een fallback is wat je app doet als de API niet op tijd kan reageren. Opties zijn het gebruiken van gecachte data, overschakelen naar een gedegradeerde modus (verberg niet-essentiële widgets, schakel optionele acties uit), vragen om gebruikersinvoer in plaats van de API te bellen (handmatige adresinvoer), of een duidelijke boodschap tonen met de volgende stap.
Wees eerlijk: zeg niet dat iets voltooid is als dat niet zo is.
Als het werk niet binnen de gebruikersrequest af hoeft te zijn, duw het naar een queue en reageer snel. Veelvoorkomende kandidaten: e-mails versturen, synchroniseren naar een CRM, rapporten genereren en analytics events posten.
Faalt snel voor kernacties. Als een API niet nodig is om checkout (of accountaanmaak) af te ronden, blokkeer het verzoek niet. Accepteer de order, zet de externe call in een queue en reconcile later. Als de API vereist is (bijv. betalingsautorisatie), faal dan snel met een duidelijke boodschap en houd de gebruiker niet wachtend.
Wat de gebruiker ziet moet overeenkomen met wat er achter de schermen gebeurt: een duidelijke status (voltooid, in afwachting, mislukt), een belofte die je kunt nakomen (bon nu, bevestiging later), een manier om opnieuw te proberen en een zichtbaar logboek in de UI (activiteitlog, pending-badge).
Rate limits zijn de manier van een provider om te zeggen: "Je kunt ons bellen, maar niet te vaak." Je raakt ze sneller dan je denkt: trafficpieken, achtergrondjobs die tegelijk draaien of een bug die in een foutlus blijft hangen.
Begin met het controleren van hoeveel requests je maakt. Batch waar mogelijk, cache responses zelfs 30–60 seconden als het veilig is, en throttle client-side zodat je app niet sneller burst dan de provider toestaat.
Als je een 429 Too Many Requests krijgt, behandel dat als een signaal om te vertragen.
Retry-After als die wordt meegegeven.Beperk ook gelijktijdigheid. Een enkele workflow (zoals contacten synchroniseren) mag niet alle workers opslokken en kritische flows zoals login of checkout verstikken. Gescheiden pools of per-feature caps helpen.
Elke third-party call heeft een plan voor falen nodig. Je hoeft geen perfectie te hebben. Je hebt voorspelbaar gedrag nodig als de provider een slechte dag heeft.
Bepaal wat er gebeurt als de call nu faalt. Een belastingberekening tijdens checkout kan een must-have zijn. Het synchroniseren van een marketingcontact kan meestal wachten. Deze keuze stuurt de rest.
Kies timeouts per calltype en houd ze consistent. Stel daarna een retry-budget in zodat je niet blijft hameren op een trage API.
Als een request iets kan aanmaken of geld kan afschrijven, voeg idempotency-keys en een request-record toe. Als een payment-request timet out, mag een retry niet dubbel afschrijven. Tracking helpt support ook bij het beantwoorden van "Is dit doorgegaan?".
Als fouten stijgen, stop met het bellen van de provider voor een korte periode. Voor must-have calls toon een duidelijke "Probeer opnieuw"-route. Voor kan-wachten calls zet het werk in een queue en verwerk het later.
Volg latency, foutpercentage en breaker open/close events. Alert bij aanhoudende veranderingen, niet bij enkele blips.
De meeste API-outages beginnen niet groot. Ze worden groot omdat je app op de slechtst mogelijke manier reageert: te lang wachten, te agressief herproberen en dezelfde workers bezet houden die alles draaiende houden.
Deze patronen veroorzaken cascades:
Kleine fixes voorkomen grote outages: herprobeer alleen fouten die waarschijnlijk tijdelijk zijn (timeouts, sommige 429s, sommige 5xx) en cap pogingen met backoff en jitter; houd timeouts kort en doelbewust; vereis idempotentie voor elke operatie die iets aanmaakt of kost; en ontwerp voor partiële uitval.
Voer voordat je een integratie in productie zet een korte controle uit met een faalmindset. Als je niet op "ja" kunt antwoorden op een item, behandel het dan als een release-blocker voor kernworkflows zoals signup, checkout of het verzenden van berichten.
Als een payment-provider begint te timen-outen, is het juiste gedrag: "checkout laadt nog steeds, de gebruiker krijgt een duidelijke boodschap en je hangt niet oneindig", niet "alles hangt totdat het time-out."
Stel je een checkout voor die drie services aanroept: een payment-API om de kaart te belasten, een tax-API om belasting te berekenen en een e-mail-API om de bon te sturen.
De payment-call is de enige die synchroon moet zijn. Problemen met tax of e-mail mogen de aankoop niet blokkeren.
Stel dat de tax-API soms 8–15 seconden nodig heeft. Als de checkout wacht, haken gebruikers af en bindt je app workers.
Een veiliger flow:
Uitkomst: minder verlaten winkelwagens en minder vastzittende orders wanneer de tax-provider traag is.
Bevestigingsmails zijn belangrijk, maar ze mogen nooit het vastleggen van de betaling blokkeren. Als de e-mail-API faalt, moet de circuit breaker na een paar snelle fouten openen en calls voor een korte cooldown stoppen.
In plaats van e-mail inline te versturen, zet je een "stuur bon"-job in de wachtrij met een idempotency-key (bijv. order_id + email_type). Als de provider down is, probeert de queue in de achtergrond opnieuw en ziet de klant nog steeds een succesvolle aankoop.
Uitkomst: minder supporttickets over ontbrekende bevestigingen en geen verloren omzet doordat checkout faalt om niet-betalingsredenen.
Kies één workflow die het meest pijn doet als die faalt (checkout, signup, facturatie) en maak die je referentie-integratie. Kopieer dan dezelfde defaults overal.
Een eenvoudige uitrolvolgorde:
Schrijf je defaults op en houd ze saai: één connect-timeout, één request-timeout, max retry-aantal, backoff-range, breaker-cooldown en de regels voor wat retryable is.
Voer een failure drill uit voordat je naar de volgende workflow gaat. Forceer timeouts (of blokkeer de provider in een testomgeving) en bevestig dat de gebruiker een nuttige boodschap ziet, fallback-paden werken en queued retries niet voor altijd opstapelen.
Als je snel nieuwe producten bouwt, is het de moeite waard om deze betrouwbaarheid-standaarden om te zetten in een herbruikbaar template. Voor teams die Koder.ai (koder.ai) gebruiken, betekent dat vaak het definiëren van timeout-, retry-, idempotency- en breakerregels één keer en daarna hetzelfde patroon toepassen bij het genereren en itereren van nieuwe services.