Einführung
Wenn Sie versuchen, etwas über das Web zu lernen
Bei der Entwicklung stellen wir normalerweise fest, dass das Front-End wesentlich zugänglicher ist als das Back-End. Dafür gibt es viele Gründe, insbesondere das Gefühl eines sofortigen Feedbacks, das entsteht, wenn man ein bestimmtes Element einer Seite im Code ändert und bemerkt, dass die Änderung auf die Website angewendet wird. Für Anfänger ist dieses Feedback oft hilfreich, da es ihnen ermöglicht, ihren Code anzupassen und aus ihren Fehlern zu lernen. Leider ist dies beim Backend nicht der Fall: Oftmals wird viel Arbeit darauf verwendet, die Umgebung im Voraus einzurichten und die erforderlichen Abhängigkeiten zu installieren, damit eine einfache
Hallo Welt
- Meldung auf dem Terminal angezeigt wird. Glücklicherweise In der Open-Source-Community werden ständig große Fortschritte gemacht, um den Entwicklungsprozess von Frameworks zu erleichtern und die Erfahrung des Entwicklers zu verbessern. NodeJs ist ein gutes Beispiel dafür. Dieses Framework ist eine sehr leistungsfähige Technologie, die das Schreiben serverseitig ermöglicht Code in Javascript ist praktisch und bietet eine Vielzahl integrierter Tools und Funktionen, die es von seinen Mitbewerbern unterscheiden. In diesem Artikel werden wir NodeJs und sein Ökosystem mit einem praktischen Ansatz erkunden und ein voll funktionsfähiges Projekt erstellen.
Was werden wir bauen?
ToDo-Anwendungen sind ein Projekt der Wahl für Anfänger, die die Frontend-Entwicklung erlernen. Aus diesem Grund haben wir uns entschieden, eine Todo-Listen-API zu erstellen. Dadurch können wir unserer Schnittstelle Datenpersistenz hinzufügen und diese Daten bearbeiten (durch Hinzufügen, Aktualisieren, Löschen von Aufgaben usw.).
Den endgültigen Code finden Sie hier.
Unsere Werkzeuge
Wir werden für dieses Projekt einen vereinfachten Tech-Stack verwenden. Es kann als Minimalversion vieler Tools betrachtet werden, die Sie in realen Projekten finden, da die übergeordneten Ideen dieselben sind. Die Details der Implementierung und die Wahl eines bestimmten Tools gegenüber einem anderen sind für den Anfang nicht wichtig.
– NodeJs ist, wie bereits erwähnt, eines der beliebtesten Javascript-Frameworks zum Erstellen serverseitiger Anwendungen.
-
ExpressJs ist ein minimales Javascript-Framework, das auf NodeJS basiert. Es beschleunigt den Entwicklungsprozess durch die Verwendung vieler integrierter Funktionen. Es wird auch als Möglichkeit zur Standardisierung der Entwicklungspraktiken in NodeJS-Projekten verwendet, um die Verwendung für Ingenieure zu erleichtern.
-
LowDB ist eine einfache In-Memory-Datenbank. Dank seiner Einfachheit können wir zeigen, wie man in einem NodeJs-Projekt mit einer Datenbank interagiert, ohne sich mit fortgeschritteneren Themen wie Bereitstellungen und Konfigurationen befassen zu müssen.
Nachdem wir nun alle Tools identifiziert haben, die wir verwenden werden, greifen wir zu unseren Tastaturen und beginnen mit dem Codieren!
Installation
Node ist auf allen Plattformen verfügbar. Alle Installationsanleitungen finden Sie auf der offiziellen Website. Windows-Benutzer sollten darauf achten, den Knoten Pfad zu Umgebungsvariablen hinzuzufügen, damit er in der Befehlszeile verwendet werden kann.
Außerdem muss npm installiert sein. Npm ist der Standard-Paketmanager für NodeJs. Dadurch können wir unsere Projektabhängigkeiten verwalten. Die Installationsanleitung finden Sie hier.
Projektinitialisierung
Gehen Sie zum Link und klonen Sie das Starterprojekt:
Dies ist ein einfaches Starter-Repository für unser Projekt. Es enthält alle Abhängigkeiten, die wir zusammen mit der Projektdateistruktur verwenden werden. Wir werden jedes Element erklären, sobald wir es erreicht haben. Öffnen Sie Ihr Terminal, navigieren Sie zum Pfad des Projekts und führen Sie den Befehl aus:
npm install
Dadurch werden alle Abhängigkeiten des in der Datei package.json angegebenen Projekts installiert. package.json ist die Datei im Stammverzeichnis jedes Javascript/NodeJs-Projekts. Sie enthält Metadaten zu letzterem und wird zur Verwaltung aller Projektabhängigkeiten, Skripte und Versionen verwendet.
Nachdem alle Abhängigkeiten installiert sind, können wir unsere Anwendung starten:
npm run start
start
ist ein Skript, das wir im Paket angegeben haben. json-Datei. Es gibt die Eintragsdatei für unsere Anwendung an, in unserem Fall app.js.
Die folgende Meldung sollte nun in Ihrem Terminal erscheinen:
Das bedeutet, dass unser Server erfolgreich gestartet ist und auf alle an Port 3000 gesendeten Anfragen wartet. Schauen wir uns app.js an und erklären, was hier passiert:
App.js ist unsere Projekteintragsdatei (und derzeit die einzige). Wir instanziieren eine Express-Anwendung mit dem Namen app, geben an, dass alle Anfragen mit der http-Methode
GET
und dem Unterpfad
/
über diese Route verarbeitet werden, übergeben eine Funktion namens Middleware, die das Anfrage- und Antwortobjekt als aufnimmt Parameter. Dies ist von entscheidender Bedeutung, da die Anfrage alle für ihre Bearbeitung erforderlichen Informationen enthält (Parameter, Anfragetext, Anfrageheader usw.) und das Antwortobjekt dasjenige ist, das an den Client zurückgegeben wird. Wir beginnen damit, dass wir einfach die Nachricht „Hallo Welt“ senden. Danach lassen wir unsere Anwendung alle eingehenden Anfragen an den angegebenen Port (in unserem Fall 3000) abhören und protokollieren die Meldung
Listening to port 3000
, um anzuzeigen, dass unsere Anwendung betriebsbereit und bereit ist, Anfragen zu empfangen.
Öffnen Sie Ihr Terminal, geben Sie in der Linkleiste
localhost:3000/
ein und drücken Sie die Eingabetaste. Dies ist der angegebene Pfad, über den wir unseren Server lokal erreichen können. Sie erhalten folgende Meldung:
Datenbank-Konfiguration
Lowdb ist eine Open-Source-Datenbank, die einfach zu benutzen ist und keine besondere Einrichtung erfordert. Die allgemeine Idee dahinter ist, alle Daten in einer lokalen json-Datei zu speichern. Nachdem LowDB installiert ist (was bereits mit der Installation aller Abhängigkeiten geschehen ist), können wir den folgenden Code in db.js einfügen:
Dieser Code ist dem in der offiziellen Dokumentation von LowDB sehr ähnlich. Wir haben ihn für unseren eigenen Anwendungsfall ein wenig angepasst. Erklären wir ihn Zeile für Zeile:
Die ersten Zeilen dienen zum Importieren der notwendigen Abhängigkeiten. "join" ist eine Utility-Funktion, die im Modul "path" verfügbar ist. Es ist eines der Kernmodule von NodeJs, das eine Menge Methoden für den Umgang mit Pfaden bietet. Low" und "JSONFile" sind die beiden Klassen, die von LowDB bereitgestellt werden. Die erste Klasse erstellt die Instanz der JSON-Datei, die unsere Daten enthalten wird. Die zweite Klasse erzeugt die eigentliche Datenbankinstanz, die mit den Daten arbeitet. Schließlich ist "lodash" eine der am häufigsten verwendeten Javascript-Bibliotheken, die eine Vielzahl von Dienstfunktionen für gängige Programmieraufgaben bietet. Wir fügen sie zu unserer Datenbankinstanz hinzu, damit wir ihre fortgeschrittenen Methoden zur Verarbeitung unserer Daten nutzen können.
Zunächst geben wir den Pfad für die Datei db.json an. Das ist die Datei, die unsere Daten enthält und an LowDB übergeben wird. Wenn die Datei unter dem angegebenen Pfad nicht gefunden wird, erstellt LowDB eine neue.
Anschließend übergeben wir den Dateipfad an den LowDB-Adapter und übergeben ihn an unsere neue LowDB-Datenbankinstanz. Die Variable "db" kann dann für die Kommunikation mit unserer Datenbank verwendet werden. Sobald die Datenbankinstanz erstellt ist, lesen wir mit db.read() aus der json-Datei. Dadurch wird das Feld "data" in unserer Datenbankinstanz gesetzt, so dass wir auf den Inhalt der Datenbank zugreifen können. Beachten Sie, dass wir dieser Zeile ein "await" vorangestellt haben. Damit wird angegeben, dass die Ausführung dieser Anweisung eine unbekannte Zeitspanne in Anspruch nehmen kann und dass der NodeJs-Prozess auf die Ausführung warten muss, bevor er mit dem Rest des Codes fortfährt. Wir tun dies, weil der Lesevorgang einen Speicherzugriff auf die angegebene Datei erfordert und die Zeit für die Ausführung dieser Art von Vorgang von den Spezifikationen Ihrer Maschine abhängt.
Da wir nun Zugriff auf das Datenfeld haben, setzen wir es als ein Objekt, das ein leeres Array von Beiträgen enthält, oder besser gesagt, wir überprüfen, ob die Datei irgendwelche früheren Daten enthält und setzen das leere Array, wenn dies nicht der Fall ist.
Schließlich führen wir db.write() aus, um die Änderungen an den Daten vorzunehmen und die Datenbankinstanz zu exportieren, damit sie in anderen Dateien unseres Projekts verwendet werden kann.
Allgemeiner Anfrage/Antwort-Workflow
Betrachten Sie das folgende Diagramm:
Es zeigt die allgemeine Architektur, die in einer Vielzahl von mit NodeJs/Express erstellten Backend-Anwendungen angewendet wird. Wenn Sie den allgemeinen Arbeitsablauf bei der Bearbeitung einer Anfrage verstehen, können Sie nicht nur NodeJs-Anwendungen erstellen und strukturieren, sondern diese Konzepte auch auf praktisch jeden technischen Stack Ihrer Wahl übertragen. Wir werden die verschiedenen Schichten, die in diesen Prozess eingreifen, untersuchen und ihre Rollen erklären:
HTTP-Request-Schicht
Dies ist die erste Schicht in unserer Anwendung. Stellen Sie sich diese Schicht als ein Gateway vor, das eine Vielzahl unterschiedlicher Anfragen von verschiedenen Clients empfängt, die dann analysiert und an den entsprechenden Teil der Anwendung weitergeleitet werden, um dort bearbeitet zu werden.
-
Router: Hier beziehen wir uns auf Express-Router, aber dieses Konzept ist in vielen Backend-Frameworks zu finden. Router sind eine Möglichkeit, die logische Verteilung in unserer Geschäftslogik auf unseren Code anzuwenden, was bedeutet, dass jeder Satz von Elementen, die ähnliche Merkmale aufweisen, durch denselben Eintrag bearbeitet wird und von den übrigen Sätzen getrennt werden kann. Dies hat den Vorteil, dass jede Komponente des Codes unabhängig von den anderen ist und leichter gewartet und erweitert werden kann. Genauer gesagt, und als Beispiel, werden alle Anfragen, die die Bedingungen des gemeinsamen URL-Pfads "/posts" erfüllen, von demselben Router behandelt. Abhängig von ihrer http-Methode (GET, POST, etc.) wird ein anderer Controller verwendet.
-
Controller: Ein Controller empfängt gefilterte Anfragen von den Routern, wendet zusätzliche Verarbeitung an und ruft die geeigneten Servicemethoden auf.
Geschäftslogik-Schicht
Diese Schicht ist je nach den spezifischen Anwendungsfällen der Anwendung und der dahinter stehenden Geschäftslogik unterschiedlich.
-
Dienste: Dienste sind eine Reihe von Methoden, die die Kernlogik der Anwendung enthalten. Sie interagieren auch mit der Datenbank durch die Verwendung von ORMs/ODMs.).
-
Dienste von Drittanbietern: Viele moderne Anwendungen entscheiden sich dafür, einen Teil der Anwendungslogik an spezielle Dienste zu delegieren, die über eine API zugänglich sind. Dienste dieser Art können Zahlungsabwicklungsdienste, Speicher für statische Dateien, Benachrichtigungen und andere sein.
-
ODM/ORM: ORMs und ODMs fungieren als Mittelsmänner zwischen den Diensten und der Datenbank. Ihre Rolle besteht darin, eine High-Level-Abstraktion auf einer Datenbank bereitzustellen, die es einem Entwickler ermöglicht, Code in der Programmiersprache seiner Wahl zu schreiben, anstatt in speziellen Datenbanksprachen wie SQL.
Data Persistence Layer
- Datenbanken: Wie bereits erwähnt, benötigen fast alle Anwendungen eine Form der Datenaufbewahrung. Dieser Teil wird von Datenbanken übernommen, und je nach Art der Daten, der Geschäftslogik und vielen anderen Überlegungen wird die Wahl einer bestimmten Datenbank gegenüber einer anderen als entscheidend für die Effizienz und die Skalierbarkeit der Anwendung angesehen.
Beispiel: Hinzufügen eines Beitrags
Nachdem wir nun die allgemeine Idee hinter der Architektur verstanden haben, wollen wir sie auf unser einfaches Beispiel anwenden. Wir werden die Funktion des Hinzufügens eines ToDo-Posts zu unserer Anwendung implementieren. Gehen wir davon aus, dass jeder Beitrag eine eindeutige ID hat, die es uns ermöglicht, ihn später in unserer Datenbank zu identifizieren, einen Titel, der ein String ist, und eine Reihenfolge, die vom Typ Integer ist. Unserem Diagramm folgend, beginnen wir mit der Implementierung des Routers. Fügen Sie den folgenden Code in die Datei index.js ein:
Dies ist unsere Router-Datei. Wir importieren express und die "addPost"-Methode aus unserem Controller (diese werden wir in Kürze implementieren), erstellen eine Instanz von express router und binden die "addPost"-Methode an unseren Router - das bedeutet, dass für jede Anfrage, die den Root-Pfad und die http-Methode "POST" hat, die "addPost"-Methode aufgerufen wird, um sie zu bearbeiten.
Bevor wir unsere Methode im Controller implementieren, referenzieren wir den neuen Router in unserer Hauptdatei app.js und geben seinen Pfad als "/posts" an: Alle Routen mit den angegebenen Pfaden werden an diesen Router weitergeleitet, damit sie von den verschiedenen Controller-Methoden verarbeitet werden können:
Wir importieren den Router und nennen ihn "posts". app.use("/posts",..) bedeutet, dass alle Anfragen mit dem Unterpfad "/posts", unabhängig von ihrer http-Methode, an den angegebenen Router weitergeleitet werden.
Weitere Änderungen an app.js umfassen den Import der Datenbankkonfigurationsdatei, damit sie ausgeführt werden kann, und die Verwendung von express.json() als Middleware, damit wir auf das Request Body-Objekt zugreifen können.
Nun, da unsere Routen festgelegt sind, können wir die Methode "addPost" in der Datei controller.js hinzufügen:
"addPost" ist eine Middleware-Funktion, die als Parameter die Anfrage, die Antwortobjekte und die nächste Funktion erhält. Wenn die nächste Funktion aufgerufen wird, geht der Prozess zur nächsten Middleware in der Kette über oder beendet die Anfrage. Im Code der Methode extrahieren wir den Titel und die Reihenfolge aus dem Anforderungskörper und übergeben diese als Parameter an die Servicefunktion "createPost". Diese Funktion nimmt die Beitragsattribute, erstellt einen neuen Beitrag und gibt ihn zurück. Sobald der neue Beitrag erstellt ist, geben wir ihn zusammen mit dem Statuscode 200 an den Client zurück, was bedeutet, dass die Anfrage erfolgreich war. Sie werden feststellen, dass unser Code in einem try/catch-Block steht, um unerwartete Fehler abzufangen und an die nächste Middleware weiterzuleiten. Es gilt als bewährte Praxis, allen Routern eine Middleware für die Fehlerbehandlung beizufügen, die den Fehler extrahiert und eine aussagekräftige Fehlermeldung an den Client zurückgibt.
Jetzt muss nur noch die Funktion "createPost" in service.js implementiert werden:
Wie wir bereits bei der Erläuterung der verschiedenen Schichten der Architektur erwähnt haben, interagiert die Serviceschicht mit der Datenspeicherlösung durch die Verwendung von ORM/ODM. In unserem Beispiel brauchen wir jedoch kein separates ORM zu verwenden, da Lowdb über eine integrierte Unterstützung für Javascript verfügt. Alle Details zur Syntax finden Sie in der Dokumentation.
Die Methode "createPost" erhält title und order als Parameter und verwendet diese, um das Post-Objekt zu erstellen. Für die eindeutige ID verwenden wir eine spezielle Bibliothek namens "nanoid", die eine eindeutige Zeichenfolge erzeugt. Wir fügen den neuen Beitrag in das Posts-Array in der Datenbank ein und schreiben diese Änderungen; der neue Beitrag wird dann von der Funktion zurückgegeben.
Jetzt, da "createPost" fertig ist, ist die Funktion zum Hinzufügen von Beiträgen fertig und einsatzbereit. Wir testen sie mit Postman, einem beliebten Tool zum Testen von APIs:
Wir wählen "POST" als http-Methode für die Anfrage zusammen mit dem angegebenen URL-Pfad "localhost:3000/posts". Wir fügen den Titel und die Reihenfolge im json-Format in den Body-Abschnitt ein und senden die Anfrage ab. Wie oben gezeigt, erhalten wir den Status 200 OK zusammen mit dem neu erstellten Beitrag.
Fazit
In diesem Projekt wurden viele Konzepte und Ideen erforscht: Wir haben gelernt, wie wir unsere Projektumgebung installieren und einrichten, wie wir LowDB für die lokale Datenpersistenz konfigurieren, die allgemeine Architektur von NodeJS/Express-Backend-Anwendungen erkunden und sehen, wie wir sie in einem einfachen Beispiel anwenden. Schließlich haben wir unsere Anwendung mit Postman getestet.
Das Ziel war es, eine vereinfachte Version all dessen zu zeigen, was bei der Entwicklung moderner Backend-Anwendungen eine Rolle spielt. Wie wir bereits gesehen haben, ist NodeJs ein leistungsstarkes Werkzeug, mit dem wir einfache und komplexe APIs erstellen können. In Kombination mit dem reichhaltigen Ökosystem von Frameworks wie Express und einer Fülle von Tools und Bibliotheken für nahezu jeden Anwendungsfall ist es eine legitime Lösung für die moderne Backend-Entwicklung - eine Lösung, die zu erlernen und zu beherrschen wir empfehlen.