Ga direct naar de inhoud
DedicatedPHP Contact

Een import-API in PHP ontwerpen met voortgang en herstelbare fouten

Ontwerp asynchrone imports in PHP met duidelijke statussen, nuttige voortgangsinformatie en herstelbare fouten. Bepaal endpoints en sleutels om duplicaten te voorkomen wanneer rijen opnieuw worden verzonden.

Diagram van een import-API in PHP met statussen, voortgang en fouten per rij

Een grote import mag er niet van afhangen dat de gebruiker een HTTP-request open laat staan, en de gebruiker mag niet in het ongewisse blijven over de vraag of het systeem nog bezig is. Een goed ontworpen API maakt van het proces een herkenbare en controleerbare operatie: het bestand wordt ontvangen, de structuur wordt gevalideerd, de gegevens worden verwerkt en het resultaat wordt gemeld, inclusief fouten die moeten worden gecorrigeerd.

De voortgang van imports in PHP volgen, maakt deel uit van het API-contract en is geen queue-technologie. Het is verstandig drie samenhangende zaken van elkaar te onderscheiden: welke status de gebruiker opvraagt, hoe het werk op de achtergrond wordt uitgevoerd en hoe een mislukte taak wordt hersteld.

Waarom je niet de hele import in één HTTP-request verwerkt

Waarom je niet de hele import in één HTTP-request verwerkt — guía visual de DedicatedPHP

Bij een synchroon request moet de client wachten. Bij een grote import kan de verwerking de limieten van de webserver, een proxy of de client zelf overschrijden. Als de verbinding wordt verbroken, kan bovendien onduidelijk zijn of sommige records al zijn gewijzigd.

Een alternatief is het verzoek te accepteren, het bestand op te slaan op een locatie die toegankelijk is voor de processor, de operatie te registreren en een identifier terug te sturen. Het werk wordt daarna uitgevoerd, buiten het oorspronkelijke request om. Een queue kan dit coördineren, maar vervangt niet de opgeslagen status die de API beschikbaar moet maken.

De acceptatiereactie bevestigt dat het verzoek is ontvangen, niet dat alle gegevens zijn geïmporteerd. Daarom moet deze reactie een opvraagbare identifier en een initiële status bevatten. De grootte en het formaat valideren kan ongeschikte bestanden afwijzen, maar garandeert niet dat elke rij geldig is.

Statussen, overgangen en resultaten definiëren

Spreek een beperkte set statussen en verifieerbare overgangen af. Een mogelijke cyclus omvat received, validating en processing, met terminale resultaten zoals completed, completed_with_errors, failed en cancelled. De namen kunnen verschillen; de betekenis moet ondubbelzinnig zijn.

completed_with_errors kan aangeven dat de geldige rijen zijn verwerkt en dat de overige rijen beschikbaar zijn om te corrigeren. Gebruik failed voor een situatie waarin het onmogelijk is om verder te gaan of een betrouwbaar resultaat vast te stellen. Meld niet alleen succes omdat het technische proces is beëindigd terwijl er gegevens niet zijn verwerkt.

  • Definieer welke statussen tijdelijk en welke terminaal zijn.
  • Documenteer wie elke overgang mag starten en onder welke voorwaarden.
  • Maak onderscheid tussen algemene fouten en fouten die bij een rij horen.
  • Vermeld aanmaak-, start- en einddatums wanneer die helpen het resultaat te interpreteren.
  • Stel geen stacktraces, interne berichten of gevoelige gegevens beschikbaar in openbare responses.

Bescherm overgangen tegen dubbele uitvoeringen en updates die buiten de juiste volgorde binnenkomen. Een terminale operatie mag door een late notificatie niet teruggaan naar processing. Voorwaardelijke updates op basis van status of versie zijn gebruikelijke manieren om gelijktijdige overschrijvingen te voorkomen.

De ontvangst scheiden van de validatie van rijen

Controleer bij ontvangst de toegangsrechten, bestandsgrootte, het bestandstype en de vereiste metadata. Een eerste validatie kan verplichte kolommen en de structuur controleren. Als het bestand niet kan worden geïnterpreteerd, wijs het dan af of beëindig de operatie voordat er gedeeltelijke wijzigingen worden toegepast zonder dat daarvoor een beleid is vastgelegd.

Validatie per rij vindt tijdens de verwerking plaats. Daarbij kunnen ontbrekende verwijzingen, ongeldige waarden of conflicten met de huidige gegevens aan het licht komen. Bepaal of geldige rijen worden verwerkt terwijl andere mislukken, of dat de operatie atomair moet zijn en moet worden teruggedraaid. De keuze hangt af van het domein en de neveneffecten, en moet voor de gebruiker duidelijk zijn.

Identificeer elke rij op een stabiele manier, met een bronsleutel of, als die ontbreekt, een verwijzing die aan de batch is gekoppeld. Sla een foutcode en een begrijpelijk bericht op. Geef fouten bij grote bestanden gepagineerd terug of via een beveiligd downloadbaar resultaat, in plaats van ze bij elke statusopvraag opnieuw te versturen.

Een workflow ontwerpen om fouten te corrigeren en opnieuw te verzenden

Het product kan toestaan dat de gebruiker het volledige bestand corrigeert en als een nieuwe import uploadt, of alleen de mislukte rijen opnieuw verzendt. De eerste optie is eenvoudiger uit te leggen, maar vereist dat al verwerkte records worden herkend wanneer het bestand opnieuw wordt verwerkt. De tweede optie voorkomt dubbel werk, maar vereist dat bronsleutels worden bewaard en dat elke nieuwe poging aan de oorspronkelijke import wordt gekoppeld.

Bied voor gedeeltelijk opnieuw verzenden een expliciete actie aan die alleen mislukte of niet-bevestigde rijen en de gecorrigeerde gegevens accepteert. Baseer je niet uitsluitend op het regelnummer: de gebruiker kan de volgorde of structuur van het bestand wijzigen. Bewaar het resultaat van de vorige poging voor auditing en valideer de ontvangen gegevens opnieuw.

Om duplicaten te voorkomen, is een stabiele identiteit per record nodig. Dat kan een externe identifier zijn of een gegenereerde en voor de rij opgeslagen sleutel. Stel een geschikte unique constraint in en bepaal of een herhaling het bestaande record moet bijwerken, moet worden afgewezen of genegeerd. Bevestigde rijen mogen in elk geval niet opnieuw neveneffecten veroorzaken. Idempotente operaties en transacties per rij of batch helpen die garantie te handhaven.

Voortgang publiceren en statusopvraging beheren

Meld het aantal verwerkte eenheden en het totaal zodra dat bekend is. Voeg de huidige fase toe, bijvoorbeeld validatie of verwerking, als dat helpt de wachttijd te verklaren. Als het totaal nog niet bekend is, meld dan de fase zonder een percentage te verzinnen. Een percentage kan misleidend zijn als de fasen sterk uiteenlopende verwerkingstijden hebben.

Je hoeft niet voor elke rij een update op te slaan. Bundel updates op basis van de kosten en het nut van de informatie en voorkom dat de client onbeperkt vaak opvraagt. De interface kan de tussenpozen tussen opvragingen vergroten en ermee stoppen zodra een terminale status is ontvangen. Notificaties zijn ook mogelijk, maar na het herladen van de pagina of verlies van verbinding moet de actuele status nog steeds kunnen worden opgehaald.

Autoriseer elke opvraging en controleer of de aanvrager toegang heeft tot die specifieke operatie. Een moeilijk te raden identifier vervangt de toegangsrechten niet. Pas dezelfde controle toe op fouten en downloadbare bestanden, en bepaal hoelang deze worden bewaard.

Opnieuw proberen, hervatten en annuleren onderscheiden

Opnieuw proberen betekent iets wat is mislukt nogmaals uitvoeren; hervatten betekent verdergaan vanaf een opgeslagen punt. Een nieuwe poging kan rijen of neveneffecten herhalen als de verwerking niet idempotent is. Bepaal voordat je deze mogelijkheid aanbiedt wat is bevestigd en hoe duplicaten worden opgespoord.

Hervatten vereist dat er voldoende informatie wordt opgeslagen om de laatst bevestigde taak te identificeren en te voorkomen dat reeds verwerkte gegevens opnieuw worden toegepast. Als de brongegevens zijn gewijzigd of een consistente voortzetting niet kan worden gegarandeerd, is het veiliger een nieuwe import aan te maken dan te beweren dat de verwerking wordt hervat.

Annuleren maakt toegepaste wijzigingen niet automatisch ongedaan. Bepaal of annuleren alleen vóór de start wordt geaccepteerd, tussen batches wordt gecontroleerd of compensatieacties vereist. Meld of de verwerking is gestopt voordat er iets is verwerkt, of er gedeeltelijke wijzigingen zijn achtergebleven, of dat onderbreken inmiddels te laat was.

Datamodel en API-workflow in PHP

Een eerste model kan een tabel imports bevatten met id, owner_id, status, stage, total_rows, processed_rows, success_rows, error_rows, file_key, created_at, started_at, finished_at en version. Sla in import_rows import_id, source_key, row_number, status en attempt_count op. Een unique constraint op import_id en source_key identificeert een rij binnen de batch. Een tabel import_errors kan de sleutel, code en een veilig bericht voor de gebruiker opslaan.

Een illustratieve REST-workflow accepteert het bestand via POST /api/imports en antwoordt met 202 Accepted en {"id":"imp_8f2a","status":"received","status_url":"/api/imports/imp_8f2a"}. De client vraagt GET /api/imports/imp_8f2a op; een response tijdens de verwerking kan er zo uitzien: {"status":"processing","stage":"applying","total_rows":1200,"processed_rows":450,"success_rows":438,"error_rows":12}. Gebruik voor het ophalen van fouten een gepagineerd endpoint, zoals GET /api/imports/imp_8f2a/errors?limit=50&cursor=....

Als het opnieuw verzenden van alleen mislukte rijen is toegestaan, kan POST /api/imports/imp_8f2a/retry-errors bronsleutels en gecorrigeerde gegevens ontvangen. Het endpoint moet sleutels afwijzen die al als verwerkt zijn geregistreerd, of deze behandelen volgens een expliciet idempotentiebeleid, en de identifier van de nieuwe poging teruggeven. Het endpoint mag niet verhullen dat er een gekoppelde nieuwe poging wordt aangemaakt in plaats van de eerdere geschiedenis te wissen.

In PHP registreert de controller de operatie en antwoordt zonder het volledige bestand in het request te verwerken. Dit fragment is pseudocode in PHP 7-stijl: het gebruikt geen named arguments en setJsonBody() staat voor een eigen adapter, niet voor een standaardmethode van PHP of een methode die tussen frameworks portable is. In een echte applicatie moet dit worden vervangen door de response van de gebruikte implementatie of het gebruikte framework:

$import = $imports->create(
    $user->id,
    $storedFile->key,
    'received'
);

$dispatcher->dispatch(new ProcessImport($import->id));

$response->setStatusCode(202);
$response->setJsonBody(array(
    'id' => $import->id,
    'status' => 'received',
    'status_url' => '/api/imports/' . $import->id
));

return $response;

Het voorbeeld laat het onderscheid tussen acceptatie en uitvoering zien, maar garandeert op zichzelf niet dat de taak duurzaam wordt geregistreerd. Coördineer het opslaan van de operatie en het verzenden van de taak, zodat een fout tussen beide stappen niet resulteert in een import die niet wordt verwerkt. Afhankelijk van de infrastructuur kan hiervoor een transactie met het outbox-patroon of een ander betrouwbaar mechanisme worden gebruikt.

Tests en checklist

Tests en checklist — guía visual de DedicatedPHP

Test geldige en ongeldige overgangen, verkeerd opgemaakte bestanden, gedeeltelijke fouten, dubbele verzoeken en onderbrekingen. Controleer dat een terminale operatie geen latere voortgangsupdates publiceert, dat de tellers consistent zijn en dat paginering van fouten de toegangsrechten respecteert. Neem ook het geval mee waarin een al verwerkte rij opnieuw wordt verzonden: er mag maar één record blijven bestaan en er mogen geen neveneffecten worden herhaald.

  • Kan de gebruiker onderscheid maken tussen ontvangst, verwerking en het eindresultaat?
  • Is bepaald of de gebruiker het bestand corrigeert en opnieuw uploadt, of alleen mislukte rijen opnieuw verzendt?
  • Voorkomen stabiele sleutels dat al geïmporteerde records worden gedupliceerd?
  • Geven de tellers bevestigde werkzaamheden weer en worden ze met een redelijke frequentie bijgewerkt?
  • Vereisen statusopvraging en het downloaden van fouten de juiste toegangsrechten?
  • Hebben opnieuw proberen, hervatten en annuleren duidelijk gedefinieerde en verifieerbare gevolgen?
  • Zijn gedeeltelijke fouten, gelijktijdigheid en gegevensbehoud getest?

Een controleerbare import is meer dan alleen een voortgangsbalk. Er zijn begrijpelijke statussen, opvraagbare resultaten en een correctiebeleid voor nodig dat bevestigde records niet opnieuw toepast. Door dit contract los te koppelen van het uitvoeringsmechanisme kan de verwerking zich verder ontwikkelen zonder de gebruiker in het ongewisse te laten.

Wil je deze ideeën toepassen op je project?Laten we uw PHP-platform bespreken.
Bekijk gerelateerde service