RESTful Συμβουλές σχεδίασης API από την εμπειρία

Ένας οδηγός εργασίας των συμβουλών σχεδιασμού API και αξιολογήσεων τάσεων.

© Nathaniel Merz - Imaginary Peaks μέσω του. 500px
  • Έχω μεταναστεύσει τις τελευταίες εκδόσεις αυτού του άρθρου στο GitHub μου!
  • https://github.com/ptboyer/restful-api-design-tips
  • ️ Νιώστε ελεύθεροι να το διαβάσετε εκεί, και αφήστε ένα αστέρι, αν σας άρεσε!
  • Τελευταία ενημέρωση στο Μεσαίο, 9 Ιουνίου 2019.
Είμαστε όλοι μαθητευόμενοι σε ένα σκάφος όπου κανείς δεν γίνεται ποτέ δάσκαλος.

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

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

Από τη δημοσίευση αυτού του άρθρου, πολλά θέματα συζήτησης σε κανάλια όπως το Reddit με βοήθησαν να προσαρμόσω και να τσίμπηξω μερικές από τις εξηγήσεις και τις θέσεις μου σχετικά με το σχεδιασμό API. Θα ήθελα να ευχαριστήσω όλους όσους συνέβαλαν στη συζήτηση και ελπίζω ότι αυτό βοηθά στην κατασκευή αυτού του άρθρου σε έναν πιο πολύτιμο πόρο για τους άλλους! (Επεξεργασία: 9 / Ιούνιος / 2019) Και τώρα είναι δύο χρόνια από τότε που δημοσίευσα για πρώτη φορά αυτό το άρθρο και είναι απίστευτο να βλέπεις ότι έχει προβληθεί 150.000 φορές και έλαβε χιλιάδες αρέσει και μετοχές και για άλλη μια φορά θέλω να εκφράσω την ευγνωμοσύνη μου σε όλους τους αναγνώστες και τους οπαδούς μου!

Έκδοση

Εάν πρόκειται να αναπτύξετε ένα API για οποιαδήποτε υπηρεσία πελάτη, θα θελήσετε να προετοιμαστείτε για ενδεχόμενη αλλαγή. Αυτό επιτυγχάνεται καλύτερα με την παροχή ενός "χώρου ονομάτων έκδοσης" για το RESTful API.

Αυτό γίνεται με την απλή προσθήκη της έκδοσης ως πρόθεμα σε όλες τις διευθύνσεις URL.

GET www.myservice.com/api/v1/posts

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

GET api.myservice.com/v1/posts

Κοινή χρήση πηγών προέλευσης (CORS)

Είναι σημαντικό να λάβετε υπόψη ότι όταν τοποθετείτε το API σας σε διαφορετικό υποτομέα, όπως το api.myservice.com, θα χρειαστείτε την εφαρμογή CORS για το backend σας εάν σκοπεύετε να φιλοξενήσετε τον ιστότοπό σας στο www.myservice.com και αναμένετε να χρησιμοποιήσετε αιτήσεις λήψης χωρίς η ανίχνευση της κεφαλίδας "Δεν υπάρχει έλεγχος πρόσβασης-επιτρέπεται-προέλευσης" παρουσιάζει σφάλματα.

Διαδρομές

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

Χρησιμοποιήστε μεθόδους HTTP

Χρησιμοποιήστε μεθόδους όπως:

  • GET για την ανάκτηση δεδομένων.
  • POST για την προσθήκη δεδομένων.
  • PUT για την ενημέρωση των δεδομένων (ως σύνολο αντικειμένου).
  • PATCH για την ενημέρωση δεδομένων (με μερικές πληροφορίες για το αντικείμενο).
  • DELETE για τη διαγραφή δεδομένων.

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

Ένα ωραίο παράδειγμα αυτού είναι η οθόνη "Ρυθμίσεις του πίνακα ελέγχου" της Tumblr, όπου μπορούν να επεξεργαστούν και να αποθηκευτούν μη κρίσιμες επιλογές σχετικά με την εμπειρία χρήστη της υπηρεσίας, ανά στοιχείο, χωρίς να χρειάζεται ένα κουμπί τελικής υποβολής φόρμας. Είναι απλά ένας πολύ πιο οργανικός τρόπος αλληλεπίδρασης με τα δεδομένα προτίμησης του χρήστη.

Εμφανίζεται η ετικέτα "Αποθηκευμένο" και στη συνέχεια εξαφανίζεται λίγο μετά την τροποποίηση της επιλογής.

Χρησιμοποιήστε Plurals

Κάνει σημασιολογική αίσθηση όταν ζητάς πολλές θέσεις από / θέσεις.

Και για λόγους καλής δεν θεωρώ / post / all με / post /: id!

// DO: οι πολλαπλοί είναι σταθεροί και λογικοί
GET / v1 / posts /: id / συνημμένα /: id / σχόλια

// ΜΗΝ: είναι μόνο ένα σχόλιο; είναι μια μορφή; και τα λοιπα.
GET / v1 / post /: id / συνημμένο /: id / σχόλιο

Σε περιπτώσεις όπως αυτές θα πρέπει απλώς να προσπαθήσετε να πλησιάσετε τον πληθυντικό όσο μπορείτε!

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

Χρησιμοποιήστε τη Φιγούρα για φιλτράρισμα σχέσεων

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

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

Αυτά / posts / x / attachments είναι καλύτερα από / attachments; postId = x. Και αυτό το / posts / x / attachments / y / σχόλια είναι πολύ καλύτερο από / σχόλια; postId = x & attachmentId = y.

Χρησιμοποιήστε περισσότερα από τα "Διαδρομικά διαστήματα"

Θα πρέπει να επιδιώξετε να διατηρήσετε το API σας όσο το δυνατόν πιο επίπεδη και να μην γεμίσετε τις διαδρομές πόρων. Αφήστε τον εαυτό σας να παρέχει επίπεδες διαδρομές σε όλες τις ενημερώσεις / διαγραφή των πόρων σας, όπως στην περίπτωση των μηνυμάτων που έχουν σχόλια, επιτρέπουν / posts /: id / comments για να φέρω τα σχόλια για μια ανάρτηση με βάση τη σχέση, αλλά και προσφορά / σχόλια /: id για να επιτραπεί η επεξεργασία σχολίων χωρίς να χρειαστεί μια λαβή για τη θέση για κάθε μία διαδρομή.

  • Μακρύτερες διαδρομές για τη δημιουργία / εξαγωγή των ένθετων πόρων από τη σχέση
  • Συντομότερες διαδρομές για την ενημέρωση / διαγραφή των πόρων βάσει του αναγνωριστικού τους.

Χρησιμοποιήστε το πλαίσιο εξουσιοδότησης για να φιλτράρετε

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

  1. Η σχέση Nest a / posts με κάτω / me με GET / me / posts, ή
  2. Χρησιμοποιήστε το τελικό σημείο των υπαρχόντων / αναρτήσεων, αλλά φιλτράρετε με τη συμβολοσειρά ερωτήματος, GET / posts? User = ή
  3. Επαναχρησιμοποίηση / αναρτήσεις για να εμφανίζονται μόνο οι δικές σας θέσεις και να εκτίθενται δημόσιες αναρτήσεις με GET / feed / posts.

Χρησιμοποιήστε ένα τελικό σημείο "Me"

Έχετε ένα τελικό σημείο όπως το GET / me για να παρέχετε βασικά δεδομένα σχετικά με το χρήστη όπως διακρίνεται μέσω της κεφαλίδας εξουσιοδότησης. Αυτό μπορεί να περιλαμβάνει πληροφορίες σχετικά με τις άδειες χρήστη / πεδία / ομάδες / θέσεις / περιόδους σύνδεσης κ.λπ. που επιτρέπουν στον πελάτη να εμφανίζει / αποκρύπτει στοιχεία και διαδρομές με βάση τα δικαιώματά σας.

Όταν πρόκειται για την παροχή τελικών σημείων για την ενημέρωση των προτιμήσεων των χρηστών, επιτρέψτε στο PATCH / me να αλλάξει αυτές τις εγγενείς τιμές.

Παροχή σελίδωσης

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

Υπάρχουν πολλοί τρόποι για να το κάνετε αυτό:

Msgstr "Από την παράμετρο

Αναμφισβήτητα το πιο εύκολο στην υλοποίηση, όπου το API δέχεται μια παράμετρο της συμβολοσειράς ερωτήματος και στη συνέχεια επιστρέφει έναν περιορισμένο αριθμό αποτελεσμάτων από αυτήν την αντιστάθμιση (συνήθως 20 αποτελέσματα).

Επίσης, καλύτερα να παρέχετε μια παράμετρο ορίου που έχει μέγιστη σκληρότητα, όπως στην περίπτωση του Twitter, με μέγιστο όριο 1000 και προεπιλεγμένο όριο 200.

Επόμενη Σελίδα Token

Το API Μέσων Google επιστρέφει μια επόμενη_μεταφορά στις απαντήσεις του εάν υπάρχουν περισσότερες πληροφορίες πέραν των περιορισμένων 20 αποτελεσμάτων ανά σελίδα. Στη συνέχεια, δέχεται το pagetoken ως μια παράμετρο για μια νέα αίτηση η οποία συνεχίζει να επιστρέφει περισσότερα αποτελέσματα με μια νέα επόμενη_μεταφορά έως ότου εξαντληθεί. Το Twitter κάνει ένα παρόμοιο πράγμα χρησιμοποιώντας ένα param που ονομάζεται next_cursor.

Απαντήσεις

Χρησιμοποιήστε φακέλους

"Δεν μου αρέσει να συγκεντρώνω δεδομένα. Εισάγει απλώς ένα άλλο κλειδί για να περιηγηθείτε σε δυνητικά πυκνό δέντρο δεδομένων. Οι πληροφορίες Meta πρέπει να πηγαίνουν στις κεφαλίδες. "
"Ένα όρισμα για την εμφύτευση δεδομένων είναι να δώσετε δύο ξεχωριστά πλήκτρα ρίζας για να δείξετε την επιτυχία της απάντησης, * data * και * error *. Ωστόσο, αναθέτω αυτήν τη διάκριση στους κώδικες κατάστασης HTTP σε περιπτώσεις σφαλμάτων. "

Αρχικά, υποστήριξα τη στάση ότι τα δεδομένα που περιβάλλουν δεν είναι απαραίτητα και ότι το HTTP παρείχε ένα επαρκές "φάκελο" από μόνο του για την παροχή απάντησης. Ωστόσο, μετά την ανάγνωση μέσω των απαντήσεων στο Reddit, μπορεί να προκύψουν διάφορα τρωτά σημεία και πιθανές αδράσεις, αν δεν έχετε φακέλους JSON.

Θα πρέπει να περιβάλλετε τις απαντήσεις δεδομένων σας!

// DO: περιβάλλεται
{
  δεδομένα: [
    {...},
    {...},
    // ...
  ]
}}

// ΜΗ ΜΗΝ περιτυλίγετε
[
  {...},
  {...},
  // ...
]
"Επιπλέον, αν θέλετε να χρησιμοποιήσετε ένα εργαλείο όπως το normalizr για την ανάλυση δεδομένων από τις απαντήσεις πελάτη, η αφαίρεση ενός φακέλου καταργεί την ανάγκη για συνεχή εξαγωγή των δεδομένων από το ωφέλιμο φορτίο απόκρισης για να το περάσει ώστε να εξομαλυνθεί".

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

Είναι επίσης σημαντικό να θεωρήσουμε ότι σε αντίθεση με κάποιες, γλώσσες όπως το JavaScript θα αξιολογήσουν τα κενά αντικείμενα ως αλήθεια! Ως εκ τούτου, είναι σημαντικό να μην επιστρέψετε ένα κενό αντικείμενο για σφάλμα ως μέρος μιας απάντησης στην περίπτωση:

// περιβάλλεται, εξαγωγή σφάλματος από το ωφέλιμο φορτίο
const {δεδομένα, σφάλμα} = ωφέλιμο φορτίο
// σφάλματα επεξεργασίας αν υπάρχουν
αν (σφάλμα) {throw ...}
// σε διαφορετική περίπτωση
const normalizedData = ομαλοποίηση (δεδομένα, σχήμα)

JSON απαντήσεις και αιτήσεις

"Όλα πρέπει να είναι σειριοποιημένα σε JSON. Εάν περιμένετε JSON από το διακομιστή, να είστε ευγενικοί και να παρέχετε στον διακομιστή JSON. Συνοχή!"

Προφανώς το "όλα" είναι υπερβολή, όπως επισημαίνουν μερικά σχόλια, αλλά προοριζόταν να αναφέρεται σε οποιοδήποτε απλό, απλό αντικείμενο που θα έπρεπε να είναι σειριοποιημένο για τη διαδικασία κατανάλωσης ή / και επιστροφής από το API.

Είναι σημαντικό να ορίσετε τους τύπους μέσων σας μέσω των κεφαλίδων και στις δύο απαντήσεις και στα αιτήματα για ένα RESTful API. Όταν ασχολείστε με το JSON, βεβαιωθείτε ότι έχετε συμπεριλάβει μια κεφαλίδα εφαρμογής / τύπου: content / json και αντίστοιχα για άλλους τύπους απόκρισης, είτε CSV είτε δυαδικά αρχεία.

Επιστρέψτε το Ενημερωμένο Αντικείμενο

Κατά την ενημέρωση οποιουδήποτε πόρου μέσω ενός PUT ή PATCH είναι καλή πρακτική να επιστρέψετε τον ενημερωμένο πόρο ως απόκριση σε ένα επιτυχημένο αίτημα POST, PUT ή PATCH!

Χρησιμοποιήστε το 204 για διαγραφές

Υπήρξαν περιπτώσεις όπου δεν είχα τίποτα να επιστρέψω από την επιτυχία μιας δράσης (δηλ. DELETE), ωστόσο αισθάνομαι ότι η επιστροφή ενός κεννού αντικειμένου μπορεί σε ορισμένες γλώσσες (όπως η Python) να αξιολογηθεί ως ψευδής και ίσως να μην είναι τόσο προφανής σε έναν ανθρώπινο εντοπισμό σφαλμάτων στην αίτησή τους.

Υποστήριξη του κωδικού κατάστασης απόκρισης 204 - χωρίς περιεχόμενο σε περιπτώσεις όπου η αίτηση ήταν επιτυχής αλλά δεν έχει περιεχόμενο για επιστροφή. Ο φάκελος της απόκρισης, σε συνδυασμό με έναν κώδικα επιτυχίας 2XX HTTP, αρκεί για να δείξει μια επιτυχημένη απάντηση χωρίς αυθαίρετες "πληροφορίες".

DELETE / v1 / posts /: id
// απάντηση - 204
{
  "δεδομένα": null
}}

Χρησιμοποιήστε τους κωδικούς κατάστασης HTTP και τις απαντήσεις σφαλμάτων

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

Μου αρέσει να χρησιμοποιώ:

για σφάλματα δεδομένων

  • 400 όταν οι ζητούμενες πληροφορίες είναι ελλιπείς ή έχουν παραμορφωθεί.
  • 422 για όταν οι ζητούμενες πληροφορίες είναι εντάξει, αλλά είναι άκυρες.
  • 404 για όταν όλα είναι εντάξει, αλλά ο πόρος δεν υπάρχει.
  • 409 για όταν υπάρχει σύγκρουση δεδομένων, ακόμη και με έγκυρες πληροφορίες.

για σφάλματα Auth

  • 401 όταν δεν παρέχεται ένα διακριτικό πρόσβασης ή δεν είναι έγκυρο.
  • 403 για όταν ένα διακριτικό πρόσβασης είναι έγκυρο, αλλά απαιτεί περισσότερα προνόμια.

για τυπικές καταστάσεις

  • 200 για όταν όλα είναι εντάξει.
  • 204 για όταν όλα είναι εντάξει, αλλά δεν υπάρχει περιεχόμενο για να επιστρέψετε.
  • 500 για όταν ο διακομιστής ρίχνει ένα σφάλμα, εντελώς απροσδόκητο.

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

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

  • Αν το πεδίο ηλεκτρονικού ταχυδρομείου λείπει, επιστρέψτε το 400.
  • Εάν το πεδίο κωδικού πρόσβασης είναι πολύ σύντομο, επιστρέψτε το 422.
  • Αν το πεδίο ηλεκτρονικού ταχυδρομείου δεν είναι έγκυρο μήνυμα ηλεκτρονικού ταχυδρομείου, επιστρέψτε το 422.
  • Εάν το μήνυμα ηλεκτρονικού ταχυδρομείου έχει ήδη ληφθεί, επιστρέψτε το 409.
"Είναι πολύ καλύτερο να καθορίσετε έναν πιο συγκεκριμένο κωδικό σειράς 4xx από απλά 400. Καταλαβαίνω ότι μπορείτε να βάζετε ό, τι θέλετε στο σώμα απάντησης για να καταργήσετε το σφάλμα, αλλά οι κωδικοί είναι πολύ πιο εύκολο να το διαβάσετε με μια ματιά." (Πηγή)

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

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

Σφάλματα επικύρωσης πεδίου

Για την επιστροφή αυτών ανά σφάλματα πεδίου, μπορεί να επιστραφεί ως εξής:

POST / v1 / μητρώο
// αίτηση
{
  "διεύθυνση ηλεκτρονικού ταχυδρομείου": "end @@ user.comx"
  "κωδικός πρόσβασης": "abc"
}}
// απάντηση - 422
{
  "λάθος": {
    "κώδικας": "FIELDS_VALIDATION_ERROR",
    "μήνυμα": "Ένα ή περισσότερα πεδία έθεσαν λάθη επικύρωσης."
    "πεδία": {
      "email": "Μη έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.",
      "password": "Ο κωδικός πρόσβασης είναι πολύ μικρός".
    }}
  }}
}}

Λειτουργικά λάθη επικύρωσης

Και για την επιστροφή λειτουργικών σφαλμάτων επικύρωσης:

POST / v1 / μητρώο
// αίτηση
{
  "ηλεκτρονικό ταχυδρομείο": "end@user.com",
  "κωδικός πρόσβασης": "κωδικός πρόσβασης"
}}
// απάντηση - 409
{
  "λάθος": {
    "κώδικας": "EMAIL_ALREADY_EXISTS",
    "μήνυμα": "Ένας λογαριασμός υπάρχει ήδη με αυτό το μήνυμα ηλεκτρονικού ταχυδρομείου".
  }}
}}

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

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

Αυθεντικοποίηση

Τα σύγχρονα APIs χωρίς κράτη, εφαρμόζουν τον έλεγχο ταυτότητας με τις μάρκες που παρέχονται συνήθως μέσω της κεφαλίδας Εξουσιοδότησης (ή ακόμα και μιας παραμέτρου ερωτήματος access_token).

Χρησιμοποιήστε αυτόματα επεκτάσιμα σύμβολα περιόδου σύνδεσης

Αρχικά σκέφτηκα ότι η έκδοση JWT για τακτικά αιτήματα API ήταν ένας πολύ καλός τρόπος για να χειριστεί τον έλεγχο ταυτότητας - μέχρι που ήθελα να ακυρώσω αυτά τα μάρκες.

Στην τελευταία αναθεώρηση αυτής της δημοσίευσης (και αναλυτικά σε ξεχωριστή δημοσίευση) έδωσα έναν τρόπο για την επανεκπομπή των JWT μέσω ενός αποθηκευμένου μυστικού πελάτη "Refresh Token" (RT), το οποίο επρόκειτο να ανταλλαγεί με νέα JWT. Ωστόσο, για να εκπνεύσουν αυτές οι JWTs, κάθε μία από αυτές περιείχε μια αναφορά στην RT που εκδίδει, οπότε αν η RT είχε ακυρωθεί / διαγραφεί, έτσι θα ήταν η JWT. Εντούτοις, αυτός ο μηχανισμός νικώνει την κατάσταση απάτης του ίδιου του JWT ...

Η λύση μου τώρα είναι απλώς να χρησιμοποιήσω ένα endpoint πόρου / σεμιναρίων για να ανταλλάξουμε διαπιστευτήρια σύνδεσης για ένα μοναδικό διακριτικό σύνδεσης (χρησιμοποιώντας το uuid4) το οποίο έχει χαστούκι και αποθηκευτεί ως γραμμή βάσης δεδομένων. Ακριβώς όπως πολλές εφαρμογές σύγχρονων, το διακριτικό δεν χρειάζεται να επανεκδοθεί αν δεν υπάρχει μεγάλη περίοδος αδράνειας (παρόμοια με το χρονικό όριο της περιόδου σύνδεσης, αλλά με την κλίμακα των εβδομάδων). Μετά την αρχική επαλήθευση ταυτότητας, κάθε μελλοντικό αίτημα προσκρούει στη ζωή του συμβόλου με τρόπο που επεκτείνεται αυτομάτως, εφόσον δεν έχει λήξει.

Δημιουργία περιόδου σύνδεσης - Σύνδεση

Μια κανονική διαδικασία σύνδεσης θα μοιάζει με:

  1. Λάβετε συνδυασμό email / κωδικού πρόσβασης με POST / συνεδρίες, επεξεργάζοντας τις περιόδους λειτουργίας ως έναν άλλο πόρο.
  2. Ελέγξτε τη διεύθυνση ηλεκτρονικού ταχυδρομείου / κωδικού πρόσβασης κατά της βάσης δεδομένων.
  3. Δημιουργήστε μια νέα σειρά βάσης δεδομένων συσκέψεων που περιέχει ένα hashed uuid4 () ως διακριτικό.
  4. Επιστρέψτε τη συμβολοσειρά συμβόλων που δεν έχει χρωματίσει στον πελάτη.

Ανανέωση συνεδρίας

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

Κάθε φορά που λαμβάνεται ένα διακριτικό από το API, δηλαδή μέσω μιας κεφαλίδας εξουσιοδότησης:

  1. Λάβετε το διακριτικό, δηλαδή από την κεφαλίδα εξουσιοδότησης.
  2. Συγκρίνετε με το hash διακριτικού, αν δεν υπάρχει σειρά αντιστοίχισης συνόδου, αυξήστε το σφάλμα ελέγχου ταυτότητας.
  3. Ελέγξτε την ιδιότητα updated_at της περιόδου σύνδεσης, εάν τώρα αν είναι μεγαλύτερη από updated_at + session_life η περίοδος σύνδεσης θεωρείται ότι έχει λήξει, διαγράψτε τη γραμμή συνόδου, αυξήστε ένα σφάλμα ελέγχου ταυτότητας.
  4. Αν υπάρχει και εξακολουθεί να ισχύει από την ενημερωμένη_ημερομηνία, ορίστε την ώρα updated_at () για να ανανεώσετε το διακριτικό.

Διαχείριση συνόδων

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

Η λήψη όλων των περιόδων σύνδεσης είναι τόσο απλή όσο:

  1. GET / session για να επιστρέψετε όλες τις περιόδους σύνδεσης που σχετίζονται με τον χρήστη σας μέσω της κεφαλίδας Εξουσιοδότησης.

Τερματισμός Συνόδου - Αποσύνδεση

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

  1. Λάβετε το διακριτικό ως μέρος μιας αίτησης DELETE / sessions / id.
  2. Συγκρίνετε με το hash του διακριτικού, διαγράψτε τη σειρά συσκέψεων που ταιριάζει.

Αποφύγετε τους Κανόνες Σύνθεσης Κωδικού

Αφού έκανα πολλή έρευνα σχετικά με τους κανόνες κωδικού πρόσβασης, έχω καταλήξει στο συμπέρασμα ότι οι κανόνες κωδικού πρόσβασης είναι μαλακοί και αποτελούν μέρος των "don'ts" του NIST, λαμβάνοντας ιδιαίτερα υπόψη ότι οι κανόνες σύνθεσης κωδικού πρόσβασης συμβάλλουν στη μείωση των έγκυρων κωδικών πρόσβασης βάσει των κανόνων ισχύος τους.

Συλλέξαμε μερικά από τα καλύτερα σημεία (από τους παραπάνω συνδέσμους) για τον χειρισμό του κωδικού πρόσβασης:

  1. Επιβάλλετε μόνο ένα ελάχιστο μήκος κωδικού πρόσβασης unicode (min. 8-10).
  2. Ελέγξτε τους κοινούς κωδικούς πρόσβασης ("password12345")
  3. Ελέγξτε τη βασική εντροπία (μην επιτρέπετε "aaaaaaaaaaaaa").
  4. Μην χρησιμοποιείτε κανόνες σύνταξης κωδικών πρόσβασης (τουλάχιστον ένα "! @ # $% &").
  5. Μη χρησιμοποιείτε συμβουλές για κωδικό πρόσβασης (rhymes με "assword").
  6. Μην χρησιμοποιείτε ερωτήσεις επαλήθευσης που βασίζονται στη γνώση (ερωτήσεις ασφαλείας).
  7. Μην εξαντλείτε τους κωδικούς πρόσβασης χωρίς λόγο.
  8. Μην χρησιμοποιείτε μηνύματα SMS για έλεγχο ταυτότητας δύο παραγόντων.
  9. Χρησιμοποιήστε ένα αλάτι κωδικού πρόσβασης 32-bit ή περισσότερο.

Αυτά τα "don'ts" θα πρέπει να κάνουν τον έλεγχο κωδικού πρόσβασης πολύ πιο εύκολο!

Meta

Χρησιμοποιήστε ένα τελικό σημείο "Έλεγχος Υγείας"

Μέσω της ανάπτυξης με το AWS, ήταν απαραίτητο να παράσχουμε έναν τρόπο για να δώσουμε μια απλή απάντηση που να δείχνει ότι η παράμετρος API είναι ζωντανή και δεν χρειάζεται να ξαναρχίσει. Είναι επίσης χρήσιμο να ελέγχετε εύκολα ποια έκδοση του API υπάρχει σε οποιαδήποτε συσκευή ανά πάσα στιγμή, χωρίς έλεγχο ταυτότητας.

GET / v1
// απάντηση - 200
{
  "κατάσταση": "τρέξιμο",
  "έκδοση": "fdb1d5e"
}}

Παρέχομαι κατάσταση και έκδοση (η οποία αναφέρεται στο git commit του API κατά το χρόνο κατασκευής του). Αξίζει επίσης να σημειωθεί ότι αυτή η τιμή δεν προέρχεται από ένα ενεργό .git repo που συνοδεύεται με το δοχείο API για το EC2. Αντίθετα, γίνεται ανάγνωση (και αποθηκεύεται στη μνήμη) κατά την αρχικοποίηση από ένα αρχείο version.txt (το οποίο παράγεται από τη διαδικασία δημιουργίας) και προεπιλογή σε __UNKNOWN__ σε περίπτωση σφάλματος ανάγνωσης ή αν το αρχείο δεν υπάρχει.

Ευχαριστούμε που το διαβάσατε!

Εάν σας άρεσε το άρθρο μου και / ή το ήθελα χρήσιμο, θα εκτιμούσα αν αφήσατε ένα χτύπημα ή δύο εδώ στο Medium και αστέρι το άρθρο μου στο GitHub ️.

Μπορείτε να αφήσετε ένα σχόλιο παρακάτω. ας μιλήσουμε!