Zo maakt u uw API's betrouwbaarder in productie
Een bestelling is betaald, maar belandt nooit in het magazijnsysteem. Een klant krijgt een foutmelding omdat de betaalprovider er net even langer over doet. Of een koppeling boekt dezelfde order drie keer in, omdat het netwerk een seconde wegviel en de verzendende partij het netjes nog eens probeerde. Dat zijn geen kleine technische incidentjes. Ze kosten omzet, ze kosten supporttijd en ze kosten vertrouwen bij klanten die er zelf niets aan kunnen doen.
De vraag hoe u uw API's betrouwbaarder maakt is daarom zelden alleen een codevraag. Het antwoord zit in de hele keten: uw applicatie, de infrastructuur eronder, de systemen van ketenpartners en de manier waarop u daar beheer op voert.
En nee, een betrouwbare API is niet een API die nooit faalt. Die bestaat niet, al helemaal niet als er vier partijen in het pad zitten. Betrouwbaar betekent iets anders: fouten lopen langs een route die u vooraf hebt bedacht, ze zijn snel terug te vinden en ze hebben zo weinig mogelijk gevolgen voor het proces erachter.
Begin bij het proces, niet bij de endpoint
Veel organisaties meten precies één ding: staat de endpoint online? Zo ja, dan is het groen. Alleen kan een API technisch prima bereikbaar zijn en zakelijk compleet nutteloos. Een orderendpoint dat binnen 200 milliseconden een foutmelding teruggeeft is beschikbaar volgens het dashboard, maar uw klant staat nog steeds stil.
Drie vragen helpen beter. Welk proces hangt aan deze koppeling? Wat gebeurt er als dat proces een uur stilstaat? En hoe snel moet het weer lopen voordat het echt pijn doet? Bij een productfeed is een uur vertraging meestal geen ramp. Bij een betaling, een voorraadmutatie of toegangscontrole is een paar minuten al te lang.
Zet die antwoorden om in cijfers waar u elkaar aan kunt houden: het percentage verzoeken dat moet slagen, de responstijd die u accepteert en de termijn waarbinnen achtergebleven berichten alsnog verwerkt zijn. Dat klinkt formeel, maar het scheelt op een slechte dag een uur discussie. U weet dan niet alleen dat er iets hapert, maar ook of het binnen of buiten de afspraak valt en wie aan zet is.
Meet signalen die ergens over gaan
Een groen vinkje op een statuspagina zegt weinig. Meet het aantal geslaagde aanvragen, de fouten uitgesplitst per type, de responstijden en het volume. Meet daarnaast wat er ná de API gebeurt. Een order kan netjes worden aangenomen, terwijl de achtergrondtaak die hem moet doorzetten een uur later stuk loopt op een ontbrekend veld.
Geef elk verzoek een eigen ID en zet dat in alle logregels. Support kan een order dan volgen van webshop naar API, van API naar database en van database naar het systeem van de vervoerder. Zonder die draad erdoorheen wordt een incident vooral veel zoeken en gokken. Hoe u die basis inricht, beschrijven we uitgebreider in ons stuk over uptime- en servermonitoring.
Duidelijke contracten voorkomen de meeste verrassingen
In de praktijk komen veel koppelingsstoringen niet door een defecte server, maar door verwachtingen die nergens zijn vastgelegd. Het ene systeem wil een bedrag als getal, het andere stuurt "12,50" als tekst. Een leverancier maakt een veld verplicht en vergeet dat te melden. Of iemand levert datums ineens in een ander formaat aan.
Behandel uw specificatie daarom als een contract. Welke endpoints zijn er, welke velden zijn verplicht, welke foutcodes kan een afnemer verwachten en wat gebeurt er bij vertraging? Versiebeheer hoort daarbij. Wijzigt u iets dat bestaande integraties kan breken, zet de nieuwe versie dan een tijd naast de oude. Afnemers stappen dan over op een moment dat hun past, in plaats van op een dinsdagochtend waarop ineens niets meer werkt.
Valideer invoer aan de rand van uw systeem en wees specifiek in de foutmelding: welk veld, welke waarde, en wat had het moeten zijn. Een kale 500 bij een verkeerd e-mailadres helpt niemand verder. Het vervuilt bovendien uw monitoring, want dan staat een typefout van een klant in dezelfde statistiek als een echte storing.
Dan idempotentie, het onderwerp uit het derde voorbeeld hierboven. Een aanroep moet veilig opnieuw verstuurd kunnen worden zonder dat een order, betaling of mutatie dubbel landt. Een idempotency key per actie, met het resultaat opgeslagen, lost dat op: komt dezelfde key nog eens langs, dan geeft u het eerdere antwoord terug in plaats van er een nieuwe order van te maken. Dat is precies het scenario waarin een client geen antwoord kreeg, niet weet of het gelukt is en het dus nog eens probeert.
Vang tijdelijke fouten gecontroleerd op
Netwerken haperen, DNS gaat soms stuk en externe diensten hebben onderhoud op het moment dat het u niet uitkomt. De vraag is niet of een afhankelijkheid uitvalt, maar wat uw systeem doet terwijl dat gebeurt. Blijft u onbeperkt wachten, dan lopen uw eigen workers vol en neemt u de storing van iemand anders over. Geeft u bij het eerste hikje op, dan gooit u werk weg dat een halve seconde later gewoon gelukt zou zijn.
Time-outs zijn de eerste verdedigingslinie. Geef iedere externe aanroep een maximale wachttijd die bij het proces past. Een klant die op een pagina wacht heeft een veel strakkere grens dan een synchronisatie die om drie uur 's nachts loopt. Eén standaardwaarde voor alles is bijna altijd verkeerd: te ruim voor de voorkant, te krap voor de batch.
Daarna komen retries, maar met beleid. Probeer opnieuw bij tijdelijke problemen, zoals een time-out, een 429 of een 503. Probeer niet opnieuw bij een validatiefout of een afgewezen token, want die uitkomst verandert niet door herhalen. Bouw de wachttijd tussen pogingen op en zet er wat variatie op, zodat u een dienst die het al zwaar heeft niet alsnog omduwt met een golf gelijktijdige retries.
Hoeft een proces niet meteen klaar te zijn, dan is een wachtrij vaak de betere keuze. De API neemt de aanvraag aan, slaat hem duurzaam op en verwerkt hem daarna asynchroon. Berichten die het na een paar pogingen niet halen, gaan naar een aparte foutwachtrij waar iemand ze kan bekijken en opnieuw aanbieden. Niets verdwijnt, en dat is het hele punt.
Daar hangt wel een voorwaarde aan. Asynchroon verwerken betekent dat de gebruiker niet direct het eindresultaat ziet. Geef dan een status terug die klopt, bijvoorbeeld "aanvraag ontvangen, u krijgt bericht zodra hij verwerkt is", en zorg dat dat bericht er daadwerkelijk komt. Snel antwoorden heeft alleen waarde als duidelijk is wat dat antwoord betekent.
Houd pieken en ketenproblemen buiten de deur
Een gewone werkdag haalt bijna elk systeem. Het gaat mis bij de uitschieters: een mailing die om tien uur de deur uitgaat, een bulkimport van een nieuwe klant, een integratie die door een bug duizenden verzoeken per minuut stuurt, of een partner die vandaag vier keer zo traag antwoordt als normaal.
Met rate limiting voorkomt u dat één afnemer de hele capaciteit opeist. Zet limieten per API-key, per klant of per endpoint. Dat is geen strafmaatregel maar bescherming van alle andere gebruikers. Geef in het antwoord wel mee wanneer opnieuw proberen zin heeft, dan hoeft de afnemer niet te gokken.
Beperk daarnaast de schade van een externe dienst die onderuit gaat. Een circuit breaker stopt tijdelijk met bellen zodra duidelijk is dat er aan de andere kant niets zinnigs uitkomt. In plaats van honderden verzoeken te laten vastlopen geeft u gecontroleerd een fout terug, of schakelt u over op een beperkte alternatieve route. Na een afkoelperiode test het systeem voorzichtig of de dienst er weer is.
Caching helpt bij gegevens die niet elke seconde hoeven te kloppen, zoals productcategorieën, landenlijsten en configuratie. Bij prijzen, voorraad en rechten is het riskant, want daar doet verouderde data echte schade. Zet dus steeds de kosten van een trage reactie naast de kosten van een verkeerd antwoord. Soms is even wachten het kleinste kwaad.
Zie het eerder dan uw klant
Monitoring is pas nuttig als het één vraag beantwoordt: moet er nu iemand iets doen? Alarmeren op elke losse fout levert binnen een week alarmmoeheid op, en dan kijkt niemand meer. Alarmeren wanneer het aandeel mislukte betalingen tien minuten achter elkaar boven uw grens blijft, is wel bruikbaar. Uw logboeken mogen alles bevatten, uw meldingen niet.
Combineer technische checks met functionele. Een endpoint kan braaf een 200 teruggeven met een leeg of half antwoord erin. Laat daarom periodiek een echte actie uitvoeren: een testorder, een inlog, een voorraadopvraag. Dan controleert u de keten zoals een gebruiker hem ervaart, in plaats van alleen de buitenkant.
Zorg dat een melding naar iets leidt waar iemand mee kan werken: recente fouten, betrokken systemen, responstijden en aantallen. Voeg tracing toe waar het kan, zodat één correlatie-ID een verzoek door alle services volgt. Dat is het verschil tussen binnen tien minuten de oorzaak aanwijzen en drie teams die ieder afzonderlijk een theorie bouwen.
Leg ook het proces eromheen vast. Wie beoordeelt een melding buiten kantooruren? Wie belt de klant of de leverancier? Wanneer schaalt u op? En wie controleert na herstel of de berichten die zijn blijven liggen alsnog zijn verwerkt? Die laatste stap wordt het vaakst vergeten, en het is precies waar stille dataschade ontstaat. Techniek zonder eigenaarschap blijft kwetsbaar.
Verander klein, ook als het haast heeft
Oude code is zelden de boosdoener. Een flink deel van de incidenten begint bij een wijziging: een snelle hotfix, een dependency-update, een aangepaste configuratie, een certificaat dat wel is vernieuwd maar op één plek nog niet is uitgerold. Vaak is dat ook hoe het misgaat met die ongeschreven verwachtingen van hierboven: de wijziging breekt een afspraak die nooit expliciet is gemaakt. Hou deployments daarom klein, herhaalbaar en omkeerbaar.
Test niet alleen uw eigen API, maar ook de afspraken met de systemen die eraan hangen. Contracttests laten zien wanneer een wijziging een bestaande afnemer breekt, voordat die afnemer het zelf ontdekt. Rol daarnaast eerst uit naar een deel van het verkeer voordat u alles omzet. En zorg dat het rollback-plan actueel is, zodat niemand tijdens een incident hoeft te improviseren met een boze klant aan de telefoon.
Schrijf tot slot op wat nu alleen in iemands hoofd zit: welke externe systemen kritisch zijn, waar sleutels en certificaten staan en wanneer ze verlopen, welke wachtrij u bij een storing als eerste controleert en wie waar toegang heeft. Dat is geen bureaucratie. Het voorkomt dat herstel afhangt van die ene collega die precies nu in het vliegtuig zit.
Eén partij die de hele stapel overziet
Zodra ontwikkeling, hosting, monitoring en support bij verschillende partijen liggen, ontstaan er grijze gebieden. De hoster ziet geen serverprobleem, de ontwikkelaar wijst naar de externe API, en de leverancier van die API begint pas te kijken als er een compleet ticket ligt. Ondertussen staat uw proces stil en legt niemand verband tussen die drie observaties.
Een partij die zowel de applicatie als de onderliggende infrastructuur kent, kan dat verband wel leggen. Bij LJPc houden we die lagen daarom bewust bij elkaar, of het nu gaat om een fout in een integratie, een capaciteitsprobleem of een achtergrondtaak die sinds vrijdagavond stilstaat.
Wilt u iets verbeteren, begin dan klein. Pak één koppeling waar het echt om geld of om klanten gaat, breng in kaart wat er gebeurt als die uitvalt, en regel dat u bij de volgende storing binnen een paar minuten weet wat er stuk is, wie handelt en hoe de achtergebleven berichten worden rechtgetrokken. Dat levert een betere API op, en vooral een rustiger operatie.