Nordlet

← Ιστολόγιο

Σχέδιο Δοκιμών Προπαραγωγής (Pre-Production Test Plan) για ένα API Λογιστικής

Ένα εγχειρίδιο αξιοπιστίας για ομάδες μηχανικής: διπλές εγγραφές, επανχρησιμοποίηση idempotency, υπογραφές webhooks, γεγονότα εκτός σειράς, δεκαδικά ποσά, scopes, κλειδώματα περιόδου και αποκατάσταση.

Nordlet Team · · 17 λεπτά ανάγνωσης

Ένας κωδικός 201 Created από ένα API λογιστικής δεν σας λέει σχεδόν τίποτα. Επιβεβαιώνει απλώς ότι ο διακομιστής απάντησε. Δεν επιβεβαιώνει ότι υπάρχει ακριβώς ένα τιμολόγιο, ότι οι χρεώσεις ισούνται με τις πιστώσεις, ότι ο αριθμός παραστατικού εκχωρήθηκε μία φορά ή ότι μια επανάληψη (retry) μετά από μια διακοπή σύνδεσης δεν θα καταχωρίσει ένα δεύτερο αντίγραφο. Οι περισσότερες διπλές εγγραφές στην παραγωγή προέρχονται από αυτό το κενό: μια τροποποίηση (mutation) ολοκληρώθηκε στον διακομιστή, ενώ ο πελάτης βρισκόταν σε κατάσταση άγνωστου αποτελέσματος και επαναλάμβανε αθόρυβα την αίτηση με ένα νέο κλειδί.

Αυτό το σχέδιο προορίζεται για ομάδες που αξιολογούν ένα API λογιστικής προτού το συνδέσουν σε πραγματικά βιβλία. Εστιάζει στη συμπεριφορά σε περίπτωση αστοχίας και όχι στα σενάρια επιτυχίας (happy paths). Κάθε ενότητα παρακάτω καθορίζει τι πρέπει να δοκιμαστεί, τι πρέπει να επαληθευτεί και τι συνιστά επιτυχία. Το πλαίσιο υλοποίησης εδώ είναι το Nordlet, του οποίου το API χρησιμοποιεί bearer keys με scopes, δεκαδικές συμβολοσειρές ποσών, κλειδιά idempotency και υπογεγραμμένα webhooks. Για ακριβή σύνταξη των endpoints και συμβόλαια αποκρίσεων (response contracts), διαβάστε τις σελίδες Συμβάσεις API και Ξεκινώντας αντί να βασίζεστε σε υποθέσεις.

Τι σημαίνει πραγματικά η «επιτυχία»

Μια δοκιμή αποδεικνύει ότι μια λογιστική ενσωμάτωση είναι ασφαλής μόνο όταν επαληθεύει τη σημασιολογία (semantics) και όχι τους κωδικούς κατάστασης. Για κάθε σενάριο, η σουίτα δοκιμών πρέπει να επιβεβαιώνει:

  • Επιχειρησιακή παρενέργεια: υπάρχει ακριβώς ένας πελάτης, ένα τιμολόγιο, μια εγγραφή ημερολογίου, μια εκχώρηση αριθμού ή μια μετάβαση κατάστασης πληρωμής.
  • Λογιστική ακεραιότητα: οι χρεώσεις ισούνται με τις πιστώσεις και η νομισματική ακρίβεια διατηρείται κατά τη σειριοποίηση (serialization).
  • Συμπεριφορά επανάληψης (replay): μια επανάληψη επιστρέφει το αρχικό αποτέλεσμα αντί για μια νέα εγγραφή.
  • Ανθεκτικότητα (durability): τα αρχεία ελέγχου (audit records) και τα γεγονότα webhook υπάρχουν μόλις ολοκληρωθεί η λειτουργία.
  • Αστοχίες χωρίς παρενέργειες: οι απορριφθείσες αιτήσεις δεν καταναλώνουν αριθμούς παραστατικών και δεν γράφουν μερικές γραμμές στο καθολικό.
  • Αποκατάσταση: ένα παροδικό σφάλμα μπορεί να επαναληφθεί χωρίς διπlοτυπία ή μόνιμη απώλεια.

Οι οδηγίες API της Google χαράζουν τα όρια με σαφήνεια: μόνο οι λειτουργίες των οποίων η επαναλαμβανόμενη εκτέλεση αφήνει την ίδια τελική κατάσταση είναι ασφαλείς για επανάληψη, και ένα API θα πρέπει να προσδιορίζει ποιες λειτουργίες είναι idempotent αντί να επαναλαμβάνει τυφλά κάθε αστοχία.

Δημιουργία ενός απομονωμένου, παρατηρήσιμου περιβάλλοντος

Χρησιμοποιήστε μια εταιρεία sandbox, όχι τα πραγματικά βιβλία παραγωγής. Μια εταιρεία sandbox του Nordlet χρησιμοποιεί τα ίδια modules και τη συμπεριφορά API μιας πραγματικής εταιρείας και φέρει σήμανση ως δεδομένα δοκιμών, καθιστώντας την ασφαλή για δοκιμές διπλοτυπίας και αστοχίας υψηλού όγκου. Αυτή η σήμανση είναι αμετάβλητη μετά τη δημιουργία, οπότε τα πραγματικά βιβλία δεν μπορούν να χαρακτηριστούν εκ των υστέρων ως δεδομένα δοκιμών. Σημειώστε ότι η χρήση του sandbox μετριέται και χρεώνεται ακριβώς όπως η χρήση σε μια πραγματική εταιρεία, οπότε υπολογίστε τον όγκο των δοκιμών σας σύμφωνα με το τιμολόγιο στο οποίο βρίσκεστε.

Πριν γράψετε οποιαδήποτε δοκιμή, προετοιμάστε:

  • Μια αποκλειστική εταιρεία sandbox με isSandbox: true.
  • Ένα κλειδί API δοκιμών με scope αποκλειστικά για τα modules που δοκιμάζονται.
  • Ένα endpoint webhook ή τοπικό τούνελ (tunnel) που διατηρεί το ακατέργαστο σώμα (raw body) της αίτησης.
  • Προ-καταχωρισμένους (seeded) πελάτες, προμηθευτές και ένα γνωστό σχέδιο λογαριασμών (chart of accounts).
  • Τουλάχιστον δύο λογιστικές περιόδους: μία ανοιχτή, μία κλειδωμένη.
  • Ένα δοκιμαστικό ρολόι ή fixture ημερομηνίας, εάν η υλοποίηση το υποστηρίζει.
  • Μια τοπική αποθήκη που καταγράφει κάθε προσπάθεια αίτησης, κλειδί idempotency, hash απόκρισης, παράδοση webhook και αποτέλεσμα συμφωνίας (reconciliation).

Μην εκτελείτε δοκιμές διπλοτυπίας σε κοινόχρηστα δεδομένα staging. Ένας ξένος πελάτης ή τιμολόγιο από προηγούμενη εκτέλεση καθιστά τις μεταγενέστερες επαληθεύσεις ασαφείς.

Το fixture σας για κάθε τροποποίηση θα πρέπει να καταγράφει τη μέθοδο, το endpoint, το πλήρες σώμα (body), το κλειδί idempotency, το scope του κλειδιού, ένα αναγνωριστικό συσχέτισης πελάτη (client correlation ID), τα χρονικά σήματα (timestamps) έναρξης και λήξης, την κατάσταση απόκρισης, τα headers, το σώμα, το ID αίτησης και το αν η σύνδεση διακόπηκε πριν φτάσει η απόκριση. Χρησιμοποιήστε σταθερές δεκαδικές συμβολοσειρές όπως "75.0000" για τα χρήματα. Το Nordlet αντιπροσωπεύει τις νομισματικές αξίες ως δεκαδικές συμβολοσειρές με έως και τέσσερα δεκαδικά ψηφία, και το παράδειγμα τιμολογίου του χρησιμοποιεί αυτή τη μορφή.

Το άλλο μισό της προετοιμασίας είναι η εισαγωγή σφαλμάτων (failure injection). Ο μηχανισμός δοκιμών σας πρέπει να μπορεί να καθυστερεί μια απόκριση, να διακόπτει μια σύνδεση TCP αφού ο διακομιστής έλαβε την αίτηση, να επιστρέφει συνθετικές αποκρίσεις 429/500/502/503/504, να επιστρέφει μη-2xx από τον δέκτη webhook, να παραδίδει το ίδιο webhook δύο φορές, να αλλάζει τη σειρά γεγονότων, να αλλοιώνει ένα byte του σώματος ενός webhook, να αλλάζει το payload ενός κλειδιού idempotency διατηρώντας το ίδιο κλειδί, να εκτελεί δύο πανομοιότυπες αιτήσεις ταυτόχρονα και να κλειδώνει μια περίοδο μεταξύ της προετοιμασίας και της καταχώρισης. Αυτά τα σενάρια αξίζουν περισσότερο από εκατοντάδες παραδείγματα επιτυχημένων διαδρομών.

Κλειδώστε το συμβόλαιο πριν γράψετε τη λογική επανάληψης

Δημιουργήστε ή ανακτήστε το σχήμα OpenAPI και συγκρίνετέ το με τον πελάτη σας. Το Nordlet δημοσιεύει τις προδιαγραφές OpenAPI στην αναφορά API και παράγει τα SDKs με τύπους από την ίδια προδιαγραφή, οπότε οι δοκιμές που βασίζονται στο σχήμα υπερτερούν των χειροποίητων υποθέσεων.

Επαληθεύστε τα υποχρεωτικά πεδία και τύπους, τα πεδία δεκαδικών συμβολοσειρών, τις μορφές ημερομηνιών και χρονικών σημμάτων, τις επιτρεπόμενες ενέργειες και scopes, τη δομή του φακέλου σφαλμάτων (error envelope), τα σχήματα γεγονότων webhook, ποιες τροποποιήσεις αποδέχονται κλειδί idempotency και ποια πεδία απόκρισης προσδιορίζουν το αντικείμενο που δημιουργήθηκε.

Κριτήρια επιτυχίας. Ο πελάτης απορρίπτει τοπικά μη έγκυρα payloads όπου το σχήμα το επιτρέπει. Οι αποκρίσεις του διακομιστή ταιριάζουν με το τεκμηριωμένο σχήμα. Μη έγκυρα δεκαδικά, κακές ημερομηνίες και ελλιπή υποχρεωτικά πεδία παράγουν δομημένα σφάλματα επικύρωσης. Δεν επιχειρείται καμία επανάληψη για ντετερμινιστική αποτυχία επικύρωσης.

Τρόπος αστοχίας προς εντοπισμό. Ένας πελάτης αναλύει το "121.0000" σε float διπλής ακρίβειας και σειριοποιεί ένα ελαφρώς διαφορετικό ποσό αργότερα. Οι ακέραιοι αριθμοί περνούν· οι γραμμές ΦΠΑ και οι κλασματικές ποσότητες αποτυγχάνουν. Δοκιμάστε τα χρήματα ως συμβολοσειρές από άκρο σε άκρο.

Εξουσιοδότηση και απομόνωση tenant

Χρησιμοποιήστε ξεχωριστά κλειδιά για ανάγνωση και εγγραφή. Στη συνέχεια, δοκιμάστε ολόκληρο το πλέγμα: λείπει κλειδί, μη έγκυρο κλειδί, έγκυρο κλειδί με ανεπαρκές scope module, έγκυρο κλειδί με το σωστό scope, κλειδί που ανήκει σε άλλη εταιρεία και προσπάθεια ανάγνωσης αντικειμένου από διαφορετική εταιρεία.

Επαληθεύσεις:

  • Τα ελλιπή ή μη έγκυρα διαπιστευτήρια επιστρέφουν 401.
  • Ένα έγκυρο κλειδί χωρίς την απαιτούμενη άδεια επιστρέφει 403.
  • Καμία λογιστική παρενέργεια δεν δημιουργείται για καμία από τις δύο αποτυχίες.
  • Μια επιτυχής αίτηση δεν μπορεί να διαβάσει ή να τροποποιήσει τα αρχεία άλλης εταιρείας.
  • Τα σφάλματα ασφαλείας δεν επαναλαμβάνονται ποτέ αυτόματα.

Κριτήριο επιτυχίας. Μπορείτε να αποδείξετε τόσο την ορθότητα της εξουσιοδότησης όσο και την απομόνωση των tenants με αναγνώσεις μετά τη δοκιμή, όχι μόνο με κωδικούς κατάστασης.

Αποδείξτε μία καθαρή συναλλαγή

Εκτελέστε μια μικρή, ντετερμινιστική ροή: δημιουργήστε ή βρείτε έναν δοκιμαστικό πελάτη, δημιουργήστε ένα τιμολόγιο με δεκαδικές συμβολοσειρές ποσών, εκδώστε το, διαβάστε το τιμολόγιο και τη λογιστική του επίδραση, διαβάστε το αρχείο ελέγχου και λάβετε το webhook. Το παράδειγμα «Ξεκινώντας» του Nordlet δείχνει την έκδοση τιμολογίου να εκχωρεί έναν συνεχόμενο αριθμό (gapless number), να ελέγχει ότι η περίοδος είναι ανοιχτή και να καταχωρεί μια ισοσκελισμένη εγγραφή ημερολογίου στην ίδια συναλλαγή.

Βεβαιωθείτε ότι το τιμολόγιο φτάνει στην αναμενόμενη κατάσταση, ότι ο αριθμός παραστατικού εκχωρείται ακριβώς μία φορά, ότι οι χρεώσεις ισούνται με τις πιστώσεις, ότι τα σύνολα ΦΠΑ και γραμμών ταιριάζουν με τον αναμενόμενο υπολογισμό στρογγυλοποίησης half-up, ότι το αρχείο ελέγχου κατονομάζει τον δρώντα και την αλλαγή, ότι το webhook παραδίδεται τελικά και ότι η απόκριση του API και μια επακόλουθη ανάγνωση συμφωνούν σχετικά με το ID και την κατάσταση του τιμολογίου.

Μια διάκριση που αξίζει να θυμάστε: η άφιξη ενός webhook δεν αποτελεί απόδειξη ότι η τροποποίηση ολοκληρώθηκε. Η απόκριση του API συν μια επαναληπτική ανάγνωση αποτελούν τις κύριες επαληθεύσεις συναλλαγών σας. Το webhook αποδεικνύει την ειδοποίηση προς τα κάτω (downstream notification) και δοκιμάζεται χωριστά.

Idempotency: ίδιο κλειδί, ίδιο σώμα

Δημιουργήστε ένα κλειδί ανά λογική επιχειρησιακή λειτουργία, όχι ένα κλειδί ανά προσπάθεια δικτύου. Στείλτε την τροποποίηση με κλειδί K και σώμα B, αποθηκεύστε το ID που δημιουργήθηκε και, στη συνέχεια, στείλτε ξανά την ακριβώς ίδια αίτηση.

Βεβαιωθείτε ότι η δεύτερη απόκριση αντιπροσωπεύει την ίδια λειτουργία, ότι το ID του αντικειμένου είναι πανομοιότυπο και ότι υπάρχει ένα επιχειρησιακό αντικείμενο, μία καταχώριση, ένας αριθμός παραστατικού, μία οικονομική επίδραση. Η επαναλαμβανόμενη απόκριση θα πρέπει να φέρει το τεκμηριωμένο header επανάληψης — x-idempotent-replay: true στην περίπτωση του Nordlet — και το ιστορικό ελέγχου δεν πρέπει να δείχνει δεύτερη τροποποίηση.

Δύο κανόνες αποθήκευσης αλλάζουν τι πρέπει να περιμένει ο βρόχος επαναληπτικών προσπαθειών (retry loop) σας, οπότε δοκιμάστε τους άμεσα: ένα αποθηκευμένο 4xx επαναλαμβάνεται όπως κάθε άλλη απόκριση, ενώ ένα 5xx δεν αποθηκεύεται καθόλου, οπότε μια επανάληψη μετά από σφάλμα διακομιστή επανεκτελεί τη λειτουργία αντί να την αναπαράγει. Τα κλειδιά λήγουν επίσης (στο Nordlet μετά από 24 ώρες), γεγονός που θέτει όριο στο πόσο χρόνο είναι διαθέσιμη η αναπαραγωγή.

Η τεκμηρίωση του Nordlet υπόσχεται ότι η προσθήκη ενός header Idempotency-Key αποτρέπει μια επαναλαμβανόμενη αίτηση από το να δημιουργήσει διπλοτυπία, και οι συμβάσεις API του καθορίζουν το ακριβές header αναπαραγωγής και την απαίτηση απόκρισης byte προς byte. Η αρχή ταιριάζει με το δημοσιευμένο μοντέλο του Stripe: ένα κλειδί προσδιορίζει τη λογική λειτουργία, οι επαναλήψεις επιστρέφουν το αποθηκευμένο αποτέλεσμα και ένα κλειδί που επαναχρησιμοποιείται με διαφορετικές παραμέτρους απορρίπτεται αντί να αλλάζει σιωπηρά.

Κριτήριο επιτυχίας. Υπάρχει ακριβώς μία μετάβαση οικονομικής κατάστασης, ασχέτως του πόσες φορές ο πελάτης στέλνει την ίδια αίτηση εντός του παραθύρου αναπαραγωγής.

Idempotency: ίδιο κλειδί, αλλαγμένο σώμα

Στείλτε την αρχική αίτηση με κλειδί K και σώμα B1, και στη συνέχεια μια δεύτερη αίτηση με κλειδί K και σώμα B2, όπου τουλάχιστον ένα ποσό, πελάτης, ημερομηνία ή γραμμή διαφέρει.

Αναμενόμενο αποτέλεσμα: η αίτηση απορρίπτεται με το τεκμηριωμένο σφάλμα επαναχρησιμοποίησης κλειδιού — το Nordlet επιστρέφει 422 idempotency_key_reuse — το αρχικό αρχείο παραμένει ανέπαφο, δεν εμφανίζεται δεύτερη εγγραφή ή αριθμός ή τροποποίηση ελέγχου, και ο πελάτης δεν το «διορθώνει» παράγοντας ένα νέο κλειδί. Η σιωπηλή αποδοχή του B2 θα έκανε τα κλειδιά επαναληπτικών προσπαθειών ανασφαλή.

Ταυτόχρονες διπλότυπες αιτήσεις

Εκτελέστε δύο πανομοιότυπες αιτήσεις με το ίδιο κλειδί την ίδια ακριβώς στιγμή. Ανάλογα με την τεκμηριωμένη συμπεριφορά, η μία εκτελείται ενώ η άλλη λαμβάνει μια σύγκρουση εν εξελίξει — το Nordlet επιστρέφει 409 idempotency_in_progress — ή και οι δύο παρατηρούν τελικά το ίδιο αποτέλεσμα.

Βεβαιωθείτε ότι και οι δύο κλήσεις δεν μπορούν να δημιουργήσουν ανεξάρτητες οικονομικές επιδράσεις, το πολύ ένας αριθμός παραστατικού εκχωρείται, μια προσωρινή σύγκρουση επαναλαμβάνεται με το ίδιο κλειδί αντί για νέο, ο τελικός πόρος είναι πλήρης και αναγνώσιμος, και το αρχείο idempotency δεν παραμένει μόνιμα κολλημένο.

Τρόπος αστοχίας. Μια βιβλιοθήκη επαναλήψεων που παράγει ένα φρέσκο UUID ανά προσπάθεια μετατρέπει μία λογική λειτουργία σε πολλές ανεξάρτητες εγγραφές και ακυρώνει εντελώς το idempotency.

Το αβέβαιο αποτέλεσμα μετά από μια διακοπή σύνδεσης

Αυτή είναι η πιο σημαντική προσομοίωση παραγωγής. Στείλτε μια τροποποίηση με κλειδί K, αφήστε τον διακομιστή να την ολοκληρώσει, διακόψτε τη σύνδεση πριν φτάσει η απόκριση, καταγράψτε το αποτέλεσμα ως άγνωστο, στη συνέχεια επαναλάβετε με το ίδιο κλειδί K και κάντε συμφωνία διαβάζοντας τα δεδομένα του πόρου και του ελέγχου.

Βεβαιωθείτε ότι η επανάληψη επιστρέφει την αρχική ή τεκμηριωμένη απόκριση αναπαραγωγής, ότι υπάρχει ακριβώς μία οικονομική παρενέργεια, ότι ο πελάτης χαρακτηρίζει τη λειτουργία ολοκληρωμένη μόνο μετά από μια επιτυχή ανάγνωση αναπαραγωγής ή συμφωνίας, και ότι δεν παράγεται νέο κλειδί. Ένα timeout δεν σημαίνει «δεν συνέβη τίποτα». Το Stripe περιγράφει το idempotency ακριβώς ως προστασία έναντι σφαλμάτων σύνδεσης όπου ο διακομιστής μπορεί να έχει επεξεργαστεί μια τροποποίηση προτού ο πελάτης προλάβει να λάβει την απόκριση.

Μια συντηρητική πολιτική επαναλήψεων

Οι αποφάσεις επαναλήψεων εξαρτώνται τόσο από το σφάλμα όσο και από το αν η λειτουργία είναι idempotent, και όχι μόνο από την HTTP μέθοδο.

Συνήθως επαναλήψιμες, διατήρηση ίδιου κλειδιού: επαναφορά σύνδεσης (connection reset) ή timeout μετά από μια idempotent τροποποίηση, 408, 429 μετά τον σεβασμό του retry-after, και 502/503/504. Μια τεκμηριωμένη απόκριση idempotency εν εξελίξει μπορεί να επαναληφθεί μετά από μια σύντομη καθυστέρηση.

Μη επαναλήψιμες χωρίς συμφωνία: σφάλματα επικύρωσης 400/422, αποτυχίες ελέγχου ταυτότητας 401/403, 404 για ελλιπή πόρο, επιχειρησιακές συγκρούσεις 409 άσχετες με κλειδί που βρίσκεται σε εξέλιξη, αλλαγμένο payload σε υφιστάμενο κλειδί και απόρριψη λόγω κλειδώματος περιόδου.

Βεβαιωθείτε για την ύπαρξη περιορισμένου εκθετικού backoff με jitter, ρητών μέγιστων προσπαθειών και χρόνου που παρήχθη, σεβασμού του retry-after για τα όρια ρυθμού (rate limits), διατήρησης του ίδιου κλειδιού σε επαναλήψεις μίας λειτουργίας, νέου κλειδιού για κάθε νέα λειτουργία και αρχείων καταγραφής (logs) που διαχωρίζουν την αρχική προσπάθεια από τις επαναλήψεις.

Δοκιμάστε τον περιορισμό ρυθμού (rate limiting) μεμονωμένα. Ξεπεράστε το τεκμηριωμένο όριο — το Nordlet επιτρέπει 300 αιτήσεις ανά λεπτό ανά κλειδί API από προεπιλογή, και ορισμένα μη πιστοποιημένα endpoints φέρουν τα δικά τους χαμηλότερα όρια ανά διεύθυνση — και στη συνέχεια επιβεβαιώστε ότι ο διακομιστής επιστρέφει την απόκριση ορίου ρυθμού, ότι ο πελάτης αναλύει το retry-after ως καθυστέρηση αντί για σφάλμα, ότι κάνει παύση αντί να βομβαρδίζει το API και ότι μια επαναλαμβανόμενη τροποποίηση που περιορίστηκε επαναχρησιμοποιεί το αρχικό κλειδί. Τα headers x-ratelimit-* αναφέρουν το υπολειπόμενο υπόλοιπο, γεγονός που αποτελεί καλή προ-επαλήθευση. Διατηρήστε τις δοκιμές ορίου ρυθμού μακριά από οικονομικές επαληθεύσεις, εκτός εάν το fixture σας μπορεί να διακρίνει μια περιορισμένη προσπάθεια από μια ολοκληρωμένη.

Επαλήθευση υπογραφής webhook

Δημιουργήστε έναν δέκτη που διατηρεί τα ακατέργαστα bytes. Για κάθε γεγονότα: καταγράψτε το ακατέργαστο σώμα, διαβάστε το header x-nordlet-signature, υπολογίστε το αναμενόμενο HMAC-SHA256 με το μυστικό συνδρομής, συγκρίνετε χρησιμοποιώντας συνάρτηση σταθερού χρόνου, αναλύστε το JSON μόνο μετά την επαλήθευση, καταγράψτε την παράδοση και επιστρέψτε ένα γρήγορο 2xx μετά την ανθεκτική αποδοχή. Το Nordlet υπογράφει ένα HMAC επί του ακατέργαστου σώματος, το στέλνει ως sha256=<hex> και επαναλαμβάνει τις παραδόσεις με εκθετικό backoff. Οι οδηγίες webhooks του Stripe ενισχύουν την επαλήθευση του αμετάβλητου ακατέργαστου σώματος με σύγκριση σταθερού χρόνου.

Εκτελέστε αρνητικές δοκιμές: σωστό σώμα και μυστικό, σωστό σώμα με λάθος μυστικό, αλλαγή ενός byte στο σώμα, επανα-σειριοποιημένο JSON με αλλαγμένα κενά, ελλιπές header, κακοσχηματισμένη υπογραφή, επαναλαμβανόμενη παλιά παράδοση εάν το σχήμα περιλαμβάνει χρονικό σήμα, και έγκυρη υπογραφή παραδοθείσα σε λάθος συνδρομή.

Κριτήρια επιτυχίας. Γίνονται αποδεκτά μόνο το σωστό ακατέργαστο σώμα και μυστικό. Οι μη έγκυρες υπογραφές λαμβάνουν μη-2xx. Τα μη έγκυρα payloads δεν εισέρχονται ποτέ στη λογιστική ουρά. Τα μυστικά παραμένουν εκτός των συνήθων αρχείων καταγραφής. Ο χειριστής αναγνωρίζει την παραλαβή μόνο αφού το γεγονότα καταγραφεί με ανθεκτικότητα.

Διπlóτυπα και εκτός σειράς webhooks

Η αξιοπιστία παράδοσης είναι ξεχωριστό πρόβλημα από το idempotency του API, και ο δέκτης πρέπει επίσης να είναι idempotent. Παραδώστε το ίδιο γεγονότα δύο φορές, παραδώστε ένα γεγονότα sale_invoice.paid πριν από ένα γεγονότα sale_invoice.issued, επιστρέψτε 500 μετά την αποθήκευση αλλά πριν από την απόκριση, και αναπαραγάγετε ένα γεγονότα που ο καταναλωτής έχει ήδη επεξεργαστεί.

Βεβαιωθείτε ότι οι διπλές παραδόσεις δεν διπλασιάζουν πληρωμές, αλλαγές καταστάσεων ή ενέργειες ημερολογίου, ότι το κλειδί αποδιδιπλοποίηση (deduplication key) χρησιμοποιεί το ID παράδοσης ή γεγονότος του παρόχου όταν υπάρχει (ή ένα τεκμηριωμένο σύνθετο κλειδί, ποτέ αυθαίρετο χρονικό σήμα), ότι τα γεγονότα εκτός σειράς δεν αντικαθιστούν ποτέ τη νεότερη κατάσταση με παλαιότερη, ότι ο καταναλωτής μπορεί να ανακτήσει την τρέχουσα κατάσταση από το API όταν η σειρά δεν επαρκεί, και ότι οι αποτυχημένες προσπάθειες καταναλωτή διοχετεύονται μέσω ουράς ή διαδρομής νεκρών μηνυμάτων (dead-letter path). Το Stripe προειδοποιεί ρητά ότι η σειρά παράδοσης δεν είναι εγγυημένη και συνιστά την αποθήκευση IDs επεξεργασμένων γεγονότων.

Διατηρήστε το endpoint ελαφρύ: επικυρώστε τη δομή, επαληθεύστε την υπογραφή, αποθηκεύστε ή βάλτε στην ουρά, αναγνωρίστε, επιστρέψτε 2xx. Η συμφωνία και οι ειδοποιήσεις ανήκουν στην ασύγχρονη επεξεργασία. Δοκιμάστε το κάνοντας την εργασία προς τα κάτω να καθυστερήσει πέραν του timeout παράδοσης· ένας σωστός δέκτης εξακολουθεί να αναγνωρίζει την παραλαβή μετά την ανθεκτική τοποθέτηση στην ουρά.

Ανοιχτές και κλειδωμένες λογιστικές περίοδοι

Το Nordlet επιβάλλει κλειδώματα περιόδου κατά την ώρα καταχώρισης σε χειροφάγραφα ημερολόγια, ροές παραστατικών και εισαγωγές, οπότε δοκιμάστε τον έλεγχο σε περισσότερα από ένα σημεία. Δημιουργήστε ισοδύναμα παραστατικά με ημερομηνία σε ανοιχτή περίοδο, σε κλειδωμένη περίοδο, στο όριο ακριβώς πριν το κλείδωμα, την πρώτη ημέρα της επόμενης ανοιχτής περιόδου, και με έγκυρη ημερομηνία παραστατικού αλλά μη έγκυρη ημερομηνία καταχώρισης εάν το API διαχωρίζει τα δύο.

Για την περίπτωση κλειδωμένης περιόδου, βεβαιωθείτε ότι η αίτηση απορρίπτεται με το τεκμηριωμένο σφάλμα κλειδώματος περιόδου — ένα 409 conflict στο Nordlet — και ότι δεν γράφονται γραμμές ημερολογίου, δεν καταναλώνεται αριθμός παραστατικού, κανένα παραστατικό δεν μεταβαίνει σε κατάσταση καταχωρημένου και δεν ενεργοποιείται webhook επιτυχίας. Η έκδοση ανοιχτής περιόδου θα πρέπει να επιτύχει με τις ίδιες οικονομικές αξίες.

Δοκιμή ανταγωνισμού (Race test). Ξεκινήστε μια καταχώριση σε ανοιχτή περίοδο, κλειδώστε την περίοδο μεσοστρατίς στην αίτηση και επιβεβαιώστε ότι η ολοκλήρωση δεν μπορεί να παρακάμψει το κλείδωμα. Το κρίσιμο κριτήριο επιτυχίας: μια ολοκληρωμένη καταχώριση δεν προσγειώνεται ποτέ σε περίοδο που ήταν κλειδωμένη πριν ολοκληρωθεί η συναλλαγή.

Ελεξιμότητα και συμφωνία (Auditability and reconciliation)

Για κάθε επιτυχή τροποποίηση, επιβεβαιώστε ότι το επιχειρησιακό αντικείμενο υπάρχει, η λογιστική εγγραφή υπάρχει με χρεώσεις ίσεες με πιστώσεις, το αρχείο ελέγχου υπάρχει, το γεγονότα webhook υπάρχει ή είναι ανακτήσιμο, και η καταγραφή λειτουργίας σας δείχνει προς το ID αντικειμένου του παρόχου με επαναλήψεις που παραπέμπουν στη ίδια λογική λειτουργία.

Για κάθε απορριφθείσα τροποποίηση, επιβεβαιώστε ότι δεν υπάρχει μερικό παραστατικό, δεν καταναλώθηκε αριθμός εκτός αν το συμβόλαιο επιτρέπει δέσμευση, δεν υπάρχει εγγραφή στο καθολικό, δεν υπάρχει webhook επιτυχίας και το σφάλμα φέρει ID αίτησης για διάγνωση. Οι συμβάσεις του Nordlet περιγράφουν την ελεξιμότητα τροποποιήσεων και τις ισoσκελισμένες καταχωρήσεις ως εγγυήσεις πλατφόρμου, με την ισορροπία να επιβάλλεται από καθυστερημένο trigger βάσης δεδομένων κατά τη στιγμή της ολοκλήρωσης και όχι μόνο από τον κώδικα εφαρμογής. Μετατρέψτε αυτές τις εγγυήσεις σε ερωτήματα συμφωνίας μετά τη δοκιμή αντί να εμπιστεύεστε την απόκριση HTTP.

Βασικός πίνακες δοκιμών

Περιοχή Ενέργεια δοκιμής Αναμενόμενη επαλήθευση Κριτήριο επιτυχίας
Πιστοποίηση Χωρίς κλειδί, μη έγκυρο κλειδί, ανεπαρκές scope Δομημένο 401/403· καμία παρενέργεια Όλες οι απορριφθείσες προσπάθειες δεν δημιουργούν λογιστικό αρχείο
Σχήμα και χρήματα Μη έγκυρο δεκαδικό, ημερομηνία, υποχρεωτικό πεδίο Σφάλμα επικύρωσης σε επίπεδο πεδίου Δεν συμβαίνει επανάληψη ή μερική εγγραφή
Κανονική καταχώριση Δημιουργία και έκδοση τιμολογίου σε ανοιχτή περίοδο Ένα παραστατικό, ένα ισοσκελισμένο ημερολόγιο, ένα αρχείο ελέγχου Η κατάσταση ανάγνωσης και το καθολικό συμφωνούν
Επανάληψη ίδιου κλειδιού Επανάληψη πανομοιότυπης τροποποίησης, ίδιο κλειδί και σώμα Αναπαραγωγή αρχικού αποτελέσματος· καμία διπλοτυπία ID αντικειμένου, αριθμός, επίδραση ημερολογίου, έλεγχος παραμένουν ενιαία
Αλλαγμένο σώμα, ίδιο κλειδί Επαναχρησιμοποίηση κλειδιού με διαφορετικό ποσό Τεκμηριωμένη απόρριψη επαναχρησιμοποίησης κλειδιού Αρχικό αρχείο ανέπαφο· τίποτα νέο δεν γράφτηκε
Διακοπή σύνδεσης Ολοκλήρωση, διακοπή, επανάληψη με ίδιο κλειδί Αναπαραγόμενο αποτέλεσμα Ακριβώς μία οικονομική παρενέργεια
Κλειδωμένη περίοδος Καταχώριση παραστατικού με ημερομηνία σε κλειδωμένη περίοδο Απόρριψη λόγω κλειδώματος περιόδου Κανένα ημερολόγιο, κανένας αριθμός, κανένα webhook επιτυχίας
Υπογραφή webhook Λάθος μυστικό, αλλαγμένο σώμα Μη-2xx από τον δέκτη Μόνο σωστό ακατέργαστο σώμα και μυστικό γίνονται αποδεκτά

Τι θα έκανα πρώτα

Εάν ο χρόνος είναι περιορισμένος, εκτελέστε τις δοκιμές με τη σειρά που εντοπίζει τα πιο δαπανηρά σφάλματα. Ξεκινήστε με την επανάληψη διακοπής σύνδεσης, επειδή αυτό το μοναδικό σενάριο παράγει τις περισσότερες πραγματικές διπλοτυπίες. Στη συνέχεια, το ζεύγος idempotency ίδιου κλειδιού και αλλαγμένου σώματος. Έπειτα τις κλειδωμένες περιόδους, καθώς μια καταχώριση σε κλειστό μήνα είναι λογιστικό πρόβλημα που αναδύεται καθυστερημένα. Η επαλήθευση υπογραφής και τα webhooks εκτός σειράς έπονται, και το πλήρες πλέγμα σχήματος και εξουσιοδότησης μπορεί να εκτελείται συνεχώς στο CI μόλις σταθεροποιηθεί ο πελάτης.

Οτιδήποτε άλλο σε αυτό το σχέδιο υποστηρίζει αυτά τα πέντε. Φέρτε τα σε πράσινη κατάσταση (green) έναντι μιας εταιρείας sandbox, με τις αναγνώσεις συμφωνίας να επιβεβαιώνουν τις παρενέργειες, και θα γνωρίζετε ότι η ενσωμάτωση είναι ασφαλής πριν αγγίξει έστω και ένα πραγματικό καθολικό. Μπορείτε να δημιουργήσετε μια εταιρεία sandbox και ένα κλειδί δοκιμών με scope μέσα σε λίγα λεπτά από το Ξεκινήστε, και να ελέγξετε ποια modules χρειάζεστε από τη λίστα δυνατοτήτων.

FAQ

Είναι μια απόκριση 2xx αρκετή για να επιβεβαιώσει ότι μια λογιστική εγγραφή πέτυχε;

Όχι. Ένας κωδικός κατάστασης επιβεβαιώνει ότι ο διακομιστής απάντησε, όχι ότι υπάρχουν ακριβώς ένα παραστατικό, μία εκχώρηση αριθμού και μία ισοσκελισμένη εγγραφή ημερολογίου. Κάθε δοκιμή τροποποίησης πρέπει να ακολουθεί την απόκριση με ανάγνωση του αντικειμένου, της λογιστικής του επίδρασης και του αρχείου ελέγχου του. Η επικίνδυνη περίπτωση είναι η αντίθετη κατεύθυνση: μια λειτουργία που ολοκληρώθηκε ενώ ο πελάτης δεν έλαβε ποτέ την απόκριση.

Πρέπει να δημιουργήσω ένα νέο κλειδί idempotency όταν μια αίτηση λήγει (timeout);

Όχι, και αυτό είναι το λάθος που προκαλεί τις περισσότερες διπλοτυπίες στην παραγωγή. Το κλειδί προσδιορίζει τη λογική επιχειρησιακή λειτουργία, όχι την προσπάθεια δικτύου. Επαναλάβετε το ίδιο κλειδί και στη συνέχεια κάντε συμφωνία διαβάζοντας τον πόρο. Μια βιβλιοθήκη επαναλήψεων που παράγει ένα φρέσκο UUID ανά προσπάθεια μετατρέπει ένα επιθυμητό τιμολόγιο σε πολλές ανεξάρτητες εγγραφές.

Τι συμβαίνει εάν επαναχρησιμοποιήσω ένα κλειδί idempotency με διαφορετικό payload;

Ένα σωστό API το απορρίπτει αντί να εφαρμόζει σιωπηρά το νέο σώμα. Το Nordlet επιστρέφει 422 idempotency_key_reuse και αφήνει το αρχικό αρχείο ανέπαφο. Ο πελάτης σας θα πρέπει να το αντιμετωπίσει ως σφάλμα προγραμματισμού προς διόρθωση, και όχι ως κατάσταση που πρέπει να παρακαμφθεί με τη δημιουργία νέου κλειδιού.

Είναι τα webhooks υποκατάστατο της ανάγνωσης του αντικειμένου που δημιουργήθηκε;

Όχι. Η παράδοση webhook αποδεικνύει την ειδοποίηση προς τα κάτω, όχι ότι η συναλλαγή ολοκληρώθηκε με τον τρόπο που περιμένετε, και η σειρά παράδοσης δεν είναι εγγυημένη. Επαληθεύστε την υπογραφή επί του ακατέργαστου σώματος, αποδιδιπλοποιήστε βάσει του ID παράδοσης ή γεγονότος και ανακτήστε την τρέχουσα κατάσταση από το API όποτε η σειρά των γεγονότων από μόνη της δεν επαρκεί για να αποφασίσετε τι άλλαξε.

Πώς δοκιμάζω την καταχώριση σε κλειδωμένη λογιστική περίοδο;

Δημιουργήστε ισοδύναμα παραστατικά σε ανοιχτή περίοδο και σε κλειδωμένη, και βεβαιωθείτε ότι η περίπτωση κλειδώματος απορρίπτεται χωρίς γραμμές ημερολογίου, χωρίς καταναλωμένο αριθμό παραστατικού, χωρίς μετάβαση κατάστασης και χωρίς webhook επιτυχίας. Στη συνέχεια, εκτελέστε την έκδοση ανταγωνισμού: ξεκινήστε μια καταχώριση σε ανοιχτή περίοδο και κλειδώστε την περίοδο μεσοστρατίς. Μια ολοκληρωμένη καταχώριση δεν πρέπει ποτέ να προσγειώνεται σε περίοδο που ήταν κλειδωμένη πριν ολοκληρωθεί η συναλλαγή.

Μπορώ να εκτελέσω δοκιμές διπλοτυπίας υψηλού όγκου σε εταιρεία sandbox;

Ναι. Μια εταιρεία sandbox συμπεριφέρεται σαν πραγματική, φέρει σήμανση δεδομένων δοκιμών και διαγράφεται αμέσως αντί μετά το παράθυρο διατήρησης, οπότε είναι το κατάλληλο μέρος για καταστροφικές δοκιμές και δοκιμές διπλοτυπίας. Η χρήση του sandbox εξακολουθεί να μετριέται και να χρεώνεται όπως η πραγματική χρήση, οπότε σχεδιάστε τον όγκο αντί να επαναλαμβάνεστε επ' αόριστον.