Eine QuickBooks-Integration, die keine Felder löscht
QuickBooks Online ersetzt bei einem Update das ganze Objekt, wenn man nichts anderes sagt, und jeder Datensatz trägt eine Version, die man zurücksenden muss. Beides landet im Formular.
Eine QuickBooks-Online-Integration geht live. Eine Woche später merkt ein Kunde, dass bei einem Lieferanten die Rechnungsadresse, die Zahlungsbedingungen und der Steuerschlüssel fehlen. Niemand hat sie gelöscht. Jemand hat über ein Formular in Ihrer Anwendung die E-Mail-Adresse des Lieferanten geändert.
Das ist das Erste, was man über diese API wissen muss, und es reicht am weitesten ins Frontend.
Ein Update ist ein Ersetzen
Die meisten APIs behandeln den Body einer Anfrage als die Felder, die man ändern will. QuickBooks Online behandelt ihn standardmäßig als das Objekt, das der Datensatz danach sein soll. Was fehlt, ist nicht unverändert - es ist leer.
Ein Formular in einer Next.js-Anwendung ist genau das, was in diese Falle läuft. Die Bearbeitungsmaske kennt drei Felder, weil drei Felder geändert werden sollen. Die Server Action bekommt drei Felder und sendet drei Felder. Die Buchhaltung hat jetzt einen Lieferanten mit drei Feldern.
Es gibt zwei Absicherungen, und beide lohnen sich. Die Anfrage kann erklären, dass sie ein Teil-Update ist - ein Parameter am Aufruf, nichts Raffiniertes. Und der Handler kann den aktuellen Datensatz lesen, die Änderung darauf anwenden und das Ganze zurücksenden, sodass die Nutzlast vollständig ist, unabhängig davon, wie die API sie auslegt.
Das Zweite kostet einen Roundtrip. Es bedeutet aber auch, dass das Verhalten nicht davon abhängt, ob jemand an ein Flag denkt - und das ist in Code, der jemandes Buchhaltung anfasst, ein guter Tausch.
Die Version gehört ins Formular
Jeder Datensatz in QuickBooks Online trägt eine Version. Ein Update muss die Version mitsenden, auf der es beruht, und hat sich der Datensatz seitdem geändert, wird das Update abgelehnt.
Das ist richtig und das gewünschte Verhalten. Es ist zugleich eine Anforderung, die am Formular landet und nicht am API-Client, und genau dort machen Teams den Fehler.
Die Seite lädt einen Datensatz in Version 7 und rendert ein Formular. Die Person tippt vier Minuten. Währenddessen bearbeitet jemand aus der Buchhaltung denselben Datensatz in QuickBooks, und er wird Version 8. Das Formular schickt Version 7 und wird abgewiesen.
Die falsche Reaktion ist, das abzufangen, die aktuelle Version zu holen und erneut zu senden - denn das verwirft stillschweigend die Änderung der Buchhaltung. Die richtige ist, der Person zu sagen, was passiert ist, und zu zeigen, was sich geändert hat. Also muss die Version Teil des Formularzustands sein, durch die Server Action mitgeführt werden, und der Konflikt muss ein sichtbares Ergebnis sein statt einer Exception in einem Log.
Das ist nützlicherweise genau das Muster für optimistische Konkurrenz, das jedes Mehrbenutzer-Formular braucht. Die Buchhaltungs-API macht es nur verbindlich.
Wo die Teile der Integration tatsächlich liegen
Die Architekturfrage ist dieselbe wie bei jeder Buchhaltungsintegration, und die Antworten lohnen die Wiederholung, weil QuickBooks eine Besonderheit hinzufügt.
Der Autorisierungs-Callback ist ein Route Handler. Zusammen mit dem
Autorisierungscode liefert QuickBooks die Kennung der autorisierten Firma, und
beides muss in dieser einen Anfrage erfasst werden - der Code ist nutzlos, wenn
man nicht weiß, zu welcher Firma er gehört. Der state-Parameter muss geprüft
und nicht nur gelesen werden, denn das verhindert, dass die Autorisierung eines
Fremden am Konto Ihres Nutzers landet.
Die Tokens gehören in eine Tabelle mit dieser Firmenkennung als Schlüssel. Nicht an den Nutzer, nicht in ein Cookie, nicht in etwas, das ein Client-Component erreichen kann. Eine Person kann mehrere Firmen autorisieren, womit die Verbindung der Datensatz ist und der Nutzer eine Referenz darauf.
Gewöhnliche Lese- und Schreibzugriffe gehören in Server Actions und Server-Components, wo die Zugangsdaten liegen und der Browser sie nie sieht.
Die lange Arbeit gehört nicht dorthin. Eine Server Action ist eine Anfrage mit einem Timeout, und ein Erstimport, ein Abstimmungslauf oder ein Nachlauf ist keine Anfrage. Das geht in eine Queue: die Server Action erzeugt einen Job-Datensatz, kehrt sofort zurück, und die Seite zeigt den Fortschritt. Das ist der häufigste strukturelle Fehler in diesen Integrationen und in der Entwicklung unsichtbar, wo die Testfirma elf Rechnungen hat.
Webhooks nennen die Kennung und sonst nichts
Ein QuickBooks-Webhook kommt an einem Route Handler an, ist signiert und sagt, dass sich eine Entität eines bestimmten Typs mit einer bestimmten Kennung geändert hat. Er sagt nicht, was sich geändert hat oder was der Datensatz jetzt enthält.
Also prüft der Handler die Signatur, schreibt die Benachrichtigung weg, kehrt schnell zurück, und ein Job holt den Datensatz danach. Das Holen inline zu machen heißt, dass die Antwortzeit Ihres Webhook-Endpunkts eine Funktion der Antwortzeit der Buchhaltungs-API ist - und eine langsame API wird zu fehlgeschlagenen Zustellungen.
Die Benachrichtigung kann auch zweimal kommen, und sie kann relativ zu Ihrer eigenen Änderung in der falschen Reihenfolge kommen. Beides ist normal. Dass der Handler gefahrlos zweimal laufen kann - und eine Benachrichtigung zu einer Version ignoriert, die er schon hält - ist der Unterschied zwischen einer Synchronisation, die konvergiert, und einer, die schwingt.
Der Kundenabgleich ist das Projekt
Die technische Arbeit oben ist zwei Wochen. Die restliche Zeit geht an eine Stelle, die nicht nach Entwicklung aussieht.
QuickBooks verlangt, dass der Anzeigename eines Kunden innerhalb einer Firma eindeutig ist. Damit sind „Acme GmbH" in Ihrer Anwendung und „Acme Gmbh" in der Buchhaltung zwei verschiedene Kunden und bleiben es, bis jemand entscheidet, welcher welcher ist. Das mal zweitausend Datensätze und ein Jahrzehnt inkonsistenter Erfassung.
Dieser Abgleich - welche Seite einen Namen besitzt, was mit den Fast-Duplikaten passiert, welches Feld der Schlüssel ist - ist ein Gespräch mit der Buchhaltung und keine Entwicklungsschätzung. Teams, die ihn als Datenimportproblem behandeln, entdecken ihn drei Wochen vor dem Launch.
Wann man das nicht baut
Wenn die Anforderung ist, dass Rechnungen in QuickBooks erscheinen und nichts zurückfließt, und das Volumen bei Dutzenden pro Monat liegt, macht ein fertiger Connector das heute Nachmittag gegen eine Gebühr. Eine zweiseitige Integration lohnt sich, wenn das Mapping für Ihr Geschäft spezifisch ist, wenn das Volumen manuelle Korrektur teuer macht, oder wenn die Daten in Ihrem eigenen System liegen müssen, um nützlich zu sein.
Sie lohnt sich nicht, um eine kleine monatliche Gebühr zu vermeiden. Die Zeit geht in die Abstimmungsregeln, und die werden nicht billiger, weil Sie den API-Client selbst geschrieben haben.
