JavaScript - vom Front-End bis zum Full-Stack-Development

Der Weg von der Front-End- zur Back-End-Entwicklung hat viele Fragen in meinem Kopf aufgeworfen. Was ist Backend-Entwicklung eigentlich, und warum muss ich es lernen? Werde ich in der Lage sein, es zu meistern?

Junior-Entwickler beginnen ihre Karriere normalerweise damit, an Frontend-Bibliotheken wie Vue.JS zu basteln, bevor sie sich entscheiden, zu etwas Anspruchsvollerem wie Node.JS umzusteigen.
Front-End-Entwickler beschäftigen sich mehr mit visuellen Elementen und statischer Code-Analyse, das bedeutet sie beschäftigen sich mehr damit, wie eine Seite für die Besucher aussieht. Daher erfordern ihre Programmiersprachenkenntnisse nichts anderes als ein wenig HTML, CSS und JavaScript.
Die Idee hinter der "Full-Stack-Developement" ist es, die Entwickler praktisch mit der gesamten Austauschdynamik zwischen Front- und Backend zu verbinden. Front-End ist nur eine Präsentationsschicht, und alle dynamischen Daten, die darauf angezeigt werden, kommen aus dem Back-End.
Full-Stack-Entwickler sind wertvolle Experten, da sie jeden Aspekt des Systems, das sie bauen, verstehen und komplexe Probleme lösen können, die mehrere Variablen beinhalten.
Jetzt, wo wir einen groben Überblick über das haben, was Full-Stack-Entwickler machen, wollen wir herausfinden, was es braucht, um den Übergang von der Front-End-Seitenentwicklung zum Back-End zu schaffen.

Node.js ist eine JavaScript-Laufzeit-Umgebung, die auf der V8-JavaScript-Engine von Chrome aufbaut. Da Node.js asynchron und ereignisgesteuert ist, wurde es entwickelt, um skalierbare Netzwerk-Applikationen zu erstellen.

Ich weiß, dass das nun erstmal viel Input ist, aber ich werde das alles in kleinere Stücke zerlegen, damit es leichter zu verstehen ist.
Schauen wir uns die Entwicklung eines fortschreitenden Frontend-Entwicklers an, der sich entschlossen hat, Node.JS anzugehen. Ich habe mich für ein Demoprojekt entschieden, da alles andere als das sich als zu kompliziert erweisen und zweifellos den Lerneffekt dieser Übung verringern könnte.

Warum ist Node.js eine Laufzeitumgebung?

Vor Node.js konnte JavaScript in einem Webbrowser nur für Aufgaben wie DOM-Manipulation, Handhabung von Benutzerereignissen auf einer Webseite oder das Senden von Anfragen an einen Webserver ausgeführt werden. Doch 2009 veröffentlichte Ryan Dahl Node.js, indem er die Ereignisschleife, die schnellste JavaScript-Engine V8 und C++ kombinierte.
Node Programme sind praktisch jeder Umgebung ausführbare Datein. Es arbeitet als eigenständige Applikation und kann unabhängig vom Browser arbeiten. Alles, was auf dem Server stattfindet, kann von Node erledigt werden, einschließlich Aufgaben wie Benutzeranfragen oder Datenbankabfragen.

Ereignisgesteuertes Node.js

Node.js erlaubt es Entwicklern, eine ereignisgesteuerte Programmierarchitektur für bestimmte Aufgaben zu verwenden.

const writer = require("getWritableStreamSomehow");
writer.write("hello, Node.js \n");
writer.on("finish", () = > {
  console.log("All writes are now complete.");
});

Im obigen Beispiel ist das getWritableStreamSomehow kein richtiges Modul. Es wird nur verwendet, um die Idee hinter ereignisgesteuerter Programmierung in Node.js zu demonstrieren.
Das Writer-Modul hat eine "on"-Funktion, die benutzt wird, um ein Ereignis auf dem beschreibbaren Stream zu behandeln. Sobald die Writer-Funktion mit der Ausgabe der "Hallo ..."-Meldung fertig ist, wird das "finish"-Event ausgelöst. Die "on"-Funktion wird zuhören und darauf warten, dass es beendet wird. Dann wird eine Callback-Funktion ausgelöst, und die Konsole wird gedruckt: "Alle Schreibvorgänge sind nun abgeschlossen.

Die asynchrone Natur von Node.js

Die asynchrone Natur von Node.js manifestiert sich in der Tatsache, dass unser geschriebener Code nicht darauf warten muss, dass lang laufende Aufgaben abgeschlossen werden. Er kann den Rest unseres Codes weiterlaufen lassen und den Callback ausführen, der unserer lang laufenden Aufgabe zugeordnet ist, wenn sie abgeschlossen ist.

const foo=()=>{
  someLongRunningFunction("some Parameter",()=>{
    // code to run when the task completes.
    console.log("long running function completed");
  });
  // do some other task.
  console.log("some other task completed");
}
foo(); 

Wenn im obigen Beispiel die Ausführung die Langläufer-Funktion erreicht, muss der unter der Funktion geschriebene Code nicht auf deren Abschluss warten. Sie wird einfach ausgeführt und die Meldung "irgendeine andere Aufgabe abgeschlossen" wird gedruckt. Einige Beispiele für langlaufende Operationen sind das Ausführen einer Datenbankabfrage, das Schreiben oder Lesen einer großen Datei aus dem Dateisystem oder das Ausführen von Anfragen an andere Server. Die Meldung "Lang laufende Aufgabe abgeschlossen" wird nur dann gedruckt, wenn diese Aufgabe abgeschlossen ist. Dies ist der Hauptgrund für die Leistung von Node.js. Es kann andere Benutzeranforderungen asynchron verarbeiten, ohne auf die Beendigung einer lang laufenden I/O-Aufgabe zu warten.
Jetzt, wo du die Grundidee hinter Node.js kennst, können wir damit anfangen, Node.js für die Entwicklung einzurichten.

Node.js für die Entwicklung einrichten

Du kannst die aktuelle stabile Version von Node von diesem Link herunterladen und installieren. Nachdem du Node.js installiert hast, öffne dein Terminal (cmd in Windows und bash bei Mac). Tippe "node" ein und drücke "enter". Wenn eine Begrüßungsnachricht mit der installierten Node-Version erscheint, sind wir startklar.
Jetzt brauchen wir einen Code-Editor, um unseren Code zu schreiben. Ich persönlich bevorzuge Visual Studio Code für die Entwicklung. Es bietet reibungslose Leistung, einen schlanken Code-Editor und viele Erweiterungen für erhöhte Produktivität. Benutze den Link unten, um den Visual Studio Code oder eine andere IDE deiner Wahl herunterzuladen und zu installieren.
In dieser Anleitung werde ich eine CRUD (steht für Create - Read - Update Delete) Applikation mit Node.js entwickeln. Zuerst werde ich damit beginnen, die Dateien für unser Projekt einzurichten.

Wir werden mit den Grundlagen beginnen und dann von da aus weitermachen. Das Endergebnis wird eine voll funktionsfähige API sein, die unsere todoApp Applikation enthüllt.

  • Erstelle in dem gewünschten Verzeichnis einen neuen Ordner mit einem beliebigen Namen deiner Wahl. Ich werde todoApp wählen.
  • Öffne den VS-Code und öffne den todoApp-Projektordner.
  • Öffne dein Terminal und wechsle in das aktuelle Arbeitsverzeichnis
  • Tippe "npminit" ein und drücke Enter. Nun werden dir eine Reihe von Fragen gestellt. Beantworte oder überspringe sie am besten, indem du die Eingabetaste drückst.

Die obige Prozedur wird eine package.json Datei im todoApp Verzeichnis erstellen. Erstelle einen neuen Ordner namens "src". Erstelle innerhalb des "src"-Ordners eine app.js-Datei.

Module abfragen/importieren

In jedem Framework müssen wir Helfer-Bibliotheken und Module importieren. Node.js Module sind einfache JavaScript-Dateien, die Funktionen, Interfaces oder Kurse zur Verwendung in unserem Code offenlegen.
In Node.js ist das Importieren von Modulen erforderlich, weil es dafür die "require" Funktion benutzt. Als Referenz ist hier eine Liste aller nativen Module, die von Node.js unterstützt werden.
In der app.js-Datei werde ich das "fs"-Modul importieren, auch bekannt als das Dateisystemmodul. Mit diesem Modul können wir Aufgaben ausführen, die mit dem Dateisystem des Hostrechners zu tun haben.
Um nicht ständig hin- und herwechseln zu müssen, erstelle bitte unter todoApp einen zweiten Ordner namens "data". In diesen Ordner werden wir später unsere Datendatei schreiben.

Schaut euch den Code unten an:

const fs = require("fs"); 
data = { name: "Sveti", age: "31" };
fs.writeFile("./data/data.json", JSON.stringify(data), (err) => {
if(!err){
    console.log("data written to file successfully");
  } 
});

Die Funktion "require" benutzt den Namen eines Moduls. Sie wird als Parameter übergeben. "require" importiert praktisch Funktionalität aus der Bibliothek in unser Quellprogramm und erlaubt uns, die darin enthaltenen Methoden zu verwenden.

In eine Datei schreiben

In der ersten Zeile habe ich eine Konstante namens "fs" definiert und ihr den Inhalt des fs-Moduls zugewiesen, der von der Funktion "require" zurückgegeben wird. Nun stehen mir alle Methoden des Dateisystem-Moduls auf der fs-Konstante als Objekt zur Verfügung.
Als nächstes schreibe ich ein einfaches JSON-Datenobjekt in eine Datei namens data.json in den Ordner "data", den wir zuvor erstellt haben. Die Funktion fs.writeFile kann die folgenden Argumente annehmen

  1. Pfad zur Datei (Typ String).
  2. Zu schreibende Daten (Typ String), bitte lies diese Dokumentation für weitere Informationen.
  3. Optionen (Hauptsächlich Dateisystem bezogen), optional
  4. Der Callback wird aufgerufen, wenn der Schreibvorgang abgeschlossen ist. Der Callback nimmt ein einzelnes Argument vom Typ err entgegen und ist ebenfalls optional.

Beachte dabei: Mit Node.js solltest du immer asynchrone Funktionen verwenden, da du so die beste Performance bekommst.

Wenn die Datei im angegebenen Pfad existiert, wird sie von der Funktion fs.writeFile überschrieben. Wenn die Datei nicht existiert, wird eine neue Datei mit dem gleichen Namen erstellt, und schreibt die Daten, die durch den zweiten Parameter übergeben werden.
Bitte beachte, dass ich das JSON-Objekt nach der Stringifizierung übergebe, da es ohne es als "Objekt" geschrieben wird.
Nach dem Schreiben der Daten, wenn der Callback ausgeführt wird, wird es einen Fehler zurückgeben, wenn dieser aufgetreten ist, oder NULL. Ich werde den Fehler mit einer einfachen "if"-Anweisung beheben. Um den obigen Code auszuführen, tippe "nodesrc /app.js" in das Terminal und drücke Enter.
Wir erhalten die Ausgabe als "Daten erfolgreich in eine Datei geschrieben". JAAA! Nun haben wir unseren ersten Node.js Code erfolgreich ausgeführt. Jetzt schauen wir uns die Datei data.json im data-Ordner an, und ja, alle Daten sind wie vorgesehen dort.

Aus einer Datei lesen

const fs = require("fs");
fs.readFile("./data/data.json", { encoding: "utf-8" }, (err, data) => {
  if (!err) {
    console.log(JSON.parse(data));
    return;
  }
  console.log(err);
});

Ich habe ein paar Daten in die Datei data.json geschrieben. Lass sie uns jetzt mal lesen. Ich werde die fs.readFile-Methode verwenden. Die fs.readFile-Funktion benötigt die folgenden drei Argumente.

  1. Pfad zur Datei (Typ String)
  2. Optionen wie Kodierung; Puffer wird standardmäßig verwendet
  3. Schließlich wird der Callback aufgerufen, wenn der Lesevorgang abgeschlossen ist. Der Callback nimmt zwei Argumente entgegen: Fehler und Daten.

Bitte beachte, dass ich die an uns zurückgesendeten Daten parse, um die zuvor geschriebenen stringifizierten Daten in ein JSON-Objekt zu konvertieren.

Lass uns nun unseren Code ausführen. Jetzt bekomme ich eine Ausgabe auf dem Terminal, da die gleichen Daten vorher geschrieben wurden:

{ name: "Sveti", age: "31" }

Aus einer Datei exportieren

Angenommen, ich baue eine Web-API für eine ToDo-App, bei der die Client-Anwendung "http-Requests" sendet, um CRUD-Operationen auf ihren ToDos auszuführen. Nun möchte ich aber die an meinen Server gesendeten Daten validieren, damit meine Datenbank oder mein Speicher nicht mit unbrauchbaren Daten vollgemüllt wird. Ich kann eine Funktion erstellen, die die Eingaben meiner Benutzer validiert.
Ich könnte diese Funktion in unserer Hauptdatei app.js erstellen, aber es ist gute Praxis, den Code immer in separate Dateien zu verschieben, um die Codebasis überschaubar zu halten.
Ich werde einen neuen Ordner namens "utils" in meinem todoApp-Ordner erstellen und eine neue Datei namens "validator.js" hinzufügen.
Nun werde ich eine neue Funktion namens "validator" erstellen. Ich werde die Benutzereingaben nur für die Länge validieren, da die Benutzer Zeit für Todos hinzufügen können, die alphanumerische Zeichen und Symbole enthalten wird, z.B. "Mache einen Spaziergang um 8:00".

const validator = (userInput) => {
  return userInput.length > 5;
};

Wenn der Benutzer ein Todo mit weniger als fünf Zeichen angibt, wird diese Funktion "false" zurückgeben. Hier kommt der Teil, in dem ich den "validator" exportieren werde, um ihn in unserer app.js Hauptdatei zu verwenden. Es gibt drei Hauptsyntaxen, um Funktionen zu exportieren:

const validator = (userInput) => {
  return userInput.length > 5;
}; 
module.exports={validator};
const validator = (userInput) => { 
  return userInput.length > 5; 
}; 
module.exports.validator=validator; 
//module.exports.anyNameYouWant=exactNameOfFunction 
module.exports.validator = (userInput) => { 
  return userInput.length > 5; 
};

Ich persönlich bevorzuge die erste Syntax. Nach dem Export werde ich diese Funktion in app.js importieren.

const { validator } = require("../utils/validator.js"); 
console.log(validator("run"));

Dies ist die gleiche "require" Funktion, die ich zuvor benutzt habe, um das "fs"-Modul zu importieren, aber dieses Mal muss ich den kompletten Pfad zur validator.js-Datei angeben, da es sich nicht um ein Modul oder eine Bibliothek handelt, die von Node selbst bereitgestellt wird.
Eine andere Sache, die man beachten sollte, ist, dass ich den Rückgabewert der benötigten Funktion als {validator} umstrukturiere, um zu vermeiden, dass unnötige Funktionen importiert werden.
Denk dran: Für externe Module und Dateien, die du importieren möchtest, musst du sie mit dem absoluten oder relativen Pfad benötigen.
Um unsere Validator-Funktion zu testen, werde ich unsere Funktion mit einer Testeingabe an console.log übergeben, um einige Ausgaben auf dem Terminal auszudrucken.

const { validator } = require("../utils/validator.js"); 
console.log(validator("run"));

Output

false

Jetzt wollen wir auf korrekte Eingabe testen.

const { validator } = require("../utils/validator.js"); 
console.log(validator("run at 9"));

Output

true

Die Validator-Funktion funktioniert also einwandfrei.
Nachdem wir nun wissen, wie man externe Funktionen in eine Applikation importiert, und uns kurz mit der Erstellung einer externen Funktion befasst haben, bei der wir eine Methode exportiert haben, werde ich nun einen Webserver mit Express erstellen.

Der Webserver mit Express.js

Ich werde einen Webserver einrichten, um die Webanfragen meines Clients zu bearbeiten. Ich kann einen Server auch mit dem nativen HTTP-Modul Node.js erstellen. Express.js minimiert jedoch einfach eine Menge Code, bietet eine saubere Code-Struktur und ist super beeindruckend. Es ist einfach zu konfigurieren und ist das beliebteste Framework von Node.js, um Restful Services zu erstellen.
Zuerst muss ich es installieren, indem ich "npm i express" eintippe und auf der Kommandozeile die Enter-Taste drücke. Nachdem ich es installiert habe, werde ich es in unsere app.js importieren. Das Einrichten eines Servers in Express erfordert nur drei Schritte. Du glaubst mir nicht? Schau selbst:

const { validator } = require("../utils/validator.js");
const express = require("express");
const server = express();
server.listen(4000, () => {
  console.log("express server is up and running");
});
  1. Zuerst habe ich Express importiert. Die require-Funktion mit dem express()-Parameter gibt eine Funktion zurück, und diese wird der Konstante "express" zugewiesen.
  2. Dann rufe ich einfach die express()-Funktion auf und weise sie einer Konstanten namens "server" zu (du kannst sie so nennen, wie du willst, aber mir persönlich gefällt dieses Setup). Sobald express hochfährt, wird ein voll funktionsfähiger HTTP-Server hochgefahren.
  3. Jetzt sind alle Serverfunktionen auf der Serverkonstante verfügbar, und sie kann auf dem Port 4000 auf Anfragen lauschen, bereit für Client-Anfragen. Die "listen"-Funktion benötigt zwei Parameter, den Port, auf dem man lauschen kann, und eine Callback-Funktion, die aufgerufen wird, wenn der Server zu lauschen beginnt.

Lass uns jetzt unseren Code ausführen, indem wir auf der Kommandozeile tippen:

node src/app.js

Nach der Ausführung des obigen Befehls wird eine Meldung angezeigt, die bestätigt, dass unser Express-Server läuft. Trotzdem wird die Codeausführung nicht gestoppt.
Kannst du dir denken, warum? Das liegt daran, dass der Server ununterbrochen läuft, und das ist es, was ein Client erwartet. Ich kann den Server stoppen, indem ich einfach Strg+C drücke.
Starte den Server neu und teste ihn, indem du eine Anfrage von deinem Browser schickst. In die Suchleiste des Browsers tippe: localhost:4000 und drücke Enter.
Zunächst zeigt dein Browserfenster eine Fehlermeldung an: "cannot GET/".

Warum erscheint diese Meldung? Obwohl mein Server auf Port 4000 lauscht, kann er noch keine GET-Anfragen im Namen der Clients bearbeiten.
Bitte benutze diesen Link, um weitere Informationen über http-Anfragen zu erhalten. Die Sache ist sicher, dass wir an dieser Stelle noch ein paar zusätzliche Zeilen Code schreiben müssen.

GET Request

Der GET Request wird verwendet, um Daten vom Server zu erhalten.

const { validator } = require("../utils/validator.js");
const express = require("express");
const server = express();
let todos = [ 
  { todo: "take a walk at 9" },
  { todo: "Appointment with dentist" },
];
server.get("/todos", (req, res) => {
  res.status(200).send(todos);
});
server.listen(4000, () => {
  console.log("express server is up and running");
});

Ich habe im obigen Code ein Array von Todos definiert und es mit zwei Beispiel-Todo-Objekten gefüllt. Das Neue ist, dass ich diesmal eine User-GET-Anfrage per "get"-Funktion bearbeite, die auf der Serverkonstante verfügbar ist. Alle HTTP-Request-Handhabungsmethoden in Express.js benötigen zwei Hauptargumente.

  1. Der Pfad (oder Anfrage-URI) in der HTTP-Methode vom Typ String
  2. Eine Callback-Funktion, die zwei Argumente als Anfrage und Antwort annimmt - das Request-Objekt wird verwendet, um zu überprüfen, welche Daten an den Server gesendet wurden, und das Response-Objekt wird verwendet, um einige Daten als Antwort an den Client zu senden.

In dieser GET /todos-Anfrage muss ich nur den Pfad der Anfrage kennen. Deshalb wird nur das Response-Objekt verwendet, um die Antwort zu senden. Später werde ich das Request-Objekt nach Bedarf verwenden.
Die send-Methode des Response-Objekts wird verwendet, um eine Antwort an den Client zurückzuschicken, und es braucht nur ein einziges Argument, nämlich die Daten, die ich zurückschicken will. Wir müssen auch den Response-Statuscode zurückschicken, damit der Client weiß, dass die Anfrage erfolgreich war, in diesem Fall ein 200.
Zuerst habe ich die "status"-Methode benutzt, um den Status zu meiner Antwort hinzuzufügen und dann "send", mit der eigentlichen Antwort unserer Todo-Daten.
Um mehr über HTTP-Statuscodes zu erfahren, kannst du gerne diesem Link folgen.
Jetzt werde ich den Express-Server stoppen und neu starten. Dies wird die letzten Code-Änderungen widerspiegeln. Lass es uns noch einmal testen. Tippe localhost:4000/todos in deinen Browser ein und drücke auf Enter.
Dein Browser sollte dir nun die logische Antwort, ein JSON Array, mit unseren Todo-Daten anzeigen.

[{"todo":"take a walk at 9"},{"todo":"Appointment with dentist"}]

Die POST-Anforderung und Express-Middleware

Die POST-Anforderung ist dazu gedacht, neue Daten in unserer Applikation zu senden oder zu erstellen. Mit der POST-Anforderung kannst du dem Hauptteil der Anfrage zusätzliche Daten hinzufügen.
Bevor unser Server weitere Anfragen bearbeiten kann, müssen wir einige zusätzliche Codierungen vornehmen.
Um alles schön aufgeräumt zu halten, erstelle eine "crud.js" Datei im Utils-Ordner und öffne sie zum Bearbeiten.

const fs = require("fs");
let todos = [];
const addTodo = (todo) => {
  todos.push(todo);
  console.log(todos);
  return new Promise((resolve, reject) => {
    fs.writeFile("./data/data.json", JSON.stringify(todos), (err) => { 
      if (err) { 
        reject(err); 
      } 
      resolve(todos.length - 1); 
    }); 
  }); 
};

Wow. So langsam wird es echt ein wenig kompliziert. Lass mich das obige Stück Code ein bisschen näher erklären.
Zuerst importiere ich das Dateisystem-Modul, wie wir vorher schon gelernt haben. Als nächstes setze ich die Variable "todos" auf ein leeres Array. Wir werden dieses Array später dynamisch füllen und alle möglichen Operationen darauf ausführen.
Du wirst bemerken, dass ich gerade eine große Umstrukturierung durchführe, die uns helfen wird, sauberen Code zu erhalten.

Meine addTodo-Methode sieht jetzt kompliziert aus. Sie nimmt die "Todo" Variable als Parametereingabe. Zuerst schiebt sie den neuen Gegenstand an das Ende des "Todo"-Arrays und dann gibt sie ein neues Promise zurück, in dem das aktualisierte "Todo"-Array lebt.
Teil des Promise ist es, den Inhalt des Todo-Arrays in die Datei zu schreiben, so wie wir es vorher getan haben. Oder nicht genau?
Außerdem statten wir unser Array mit einem numerischen Index aus, so dass jeder Eintrag eine Eintrags-ID enthält. Dies ermöglicht einfachere Operationen mit unseren Daten, wenn wir sie in einem späteren Stadium unserer App aktualisieren oder löschen müssen.
Da wir gerade die Datei crud.js erstellt haben, wollen wir sie in unserer Hauptdatei app.js verwenden und einen POST-Anforderungs-Handler hinzufügen.
Bevor wir irgendeinen anderen Code schreiben, brauchen wir ein Werkzeug, um mit APIs zu arbeiten. Ich werde Postman herunterladen und installieren, um meine POST-Anforderung zu testen. Starte nach der Installation Postman.

1. Lass uns eine neue Anfragen-Sammlung erstellen und sie Todo nennen.

Postman Configuration

2. Klicke nun auf den Optionsknopf neben der Todo-Sammlung und füge eine Anfrage mit dem Namen post todo hinzu.

Postman Configuration

3. Wähle einen Beitrag aus dem Drop-Down-Menü und in der Suchleiste aus und gib localhost:4000/todo ein

Postman Configuration

Jetzt, wo der Postman fertig und bereit ist, lass uns zurückgehen und etwas Code schreiben.
Für die GET-Anfrage muss unsere API nur den Pfad der Anfrage kennen. Für die POST-Anforderung müssen wir jedoch den Body der Anfrage in ein JSON-Objekt parsen.
Um den Body der Anfrage zu parsen, müssen wir eine Middleware hinzufügen, die den Body der Anfrage von JSON parst und ihn an den designierten Request-Handler weiterleitet. Middleware ist eine Zwischenfunktion, die aufgerufen wird, bevor sie die angegebene Funktion erreicht. Middleware-Funktionen haben Zugriff sowohl auf Anfrage- als auch auf Antwortobjekte. Um eine Middleware in Express hinzuzufügen, müssen wir eine Funktion an die Use-Methode des Servers übergeben.

const { validator } = require("../utils/validator.js"); 
const express = require("express"); 
const server = express(); 
server.use(express.json());

Die Funktion "use" wird verwendet, um Middleware-Funktionen auf einem Express-Server hinzuzufügen. Die Middleware-Funktion, die an die "use" Funktion übergeben wird, wird aufgerufen, bevor sie einen bestimmten Request-Handler, den POST-Request-Handler, erreicht. Die express.json-Funktion wird bei der POST-Anforderung des Benutzers aufgerufen. Bevor sie zum POST-Request-Handler geht, wird express.json den Request-Body an JSON parsen und ihn an den POST-Request-Handler übergeben. Lass uns nun die POST-Anforderung bearbeiten.

const { addTodo } = require("../utils/crud.js");
server.post("/todo", async (req, res) => { 
  let { todo } = req.body;
  if (!validator(todo)) {
    res.status(400).send("Error! Your todo cannot be saved"); 
    return; 
  }
  let todoID = await addTodo(todo);
  res.status(200).send({
    id: todoID, 
    msg: "Your todo has been saved successfully!", 
  });
});

Beachte, dass ich in meiner POST-Anforderung einen Async-Callback weitergebe, weil ich hier "await" verwenden muss. Da wir bereits die express.json-Middleware gesetzt haben, ist der Body der POST-Anforderung bereit zur Verwendung, und ich zerstöre ihn als Todo-Array.

Zuerst validiere ich das Todo. Jeder Validierungsfehler wird an den Client zurückgeschickt. Das Todo wird mit der addTodo-Methode, die ich zuvor bei erfolgreicher Validierung erstellt habe, in die data.json-Datei geschrieben. Der Index des zurückgegebenen Todos wird mit einer Erfolgsmeldung an den Client gesendet. Wir müssen den Server erneut neu starten.

Beachte: Das Neustarten eines Express-Servers kann frustrierend und ärgerlich sein. Bitte installiere ein anderes Dienstprogramm namens Nodemon, das unseren Server automatisch neu startet, sobald es eine Änderung an unseren Node-Javascript-Quelldateien feststellt.

Gib folgende Zeile der Befehlszeile ein,

npm i nodemon --save-dev

und drücke Enter. Die --save-dev Flagge wird Nodemon als Entwicklungsabhängigkeit installieren. Jetzt werde ich den Server zum letzten Mal herunterfahren und ihn neustarten, indem ich folgendes eintippe:

nodemon src/app.js

Mein Server wird jetzt neu gestartet, und zwar jedes Mal, wenn ich eine meiner Quelldateien speichere.
Lass uns den POST-Handler testen, um Todo auf einem Post-Anforderungs-Body hinzuzufügen, müssen wir auf den Body-Tab auf Postman klicken und dann JSON wählen, wie gezeigt.

Postman Configuration

Ich werde der Anfrage ein Beispiel-Todo hinzufügen, indem ich folgendes eintippe,

{
  "todo":"Do a good run at the park"
}

Sobald du den obigen JSON-Code hinzugefügt hast, klicke auf "Send". Um die Antwort des Servers zu überprüfen, scrolle ein wenig nach unten.

{
  "id": 1,
  "msg": "Your todo has been saved successfully!"
}

Der Server bearbeitet unsere Anfrage korrekt.

Refactoring der GET-Anfrage

Lass uns eine readTodos-Methode in unsere crud.js-Datei schreiben.

const readTodos = () => { 
  return new Promise((resolve, reject) => { 
    fs.readFile("./data/data.json", { encoding: "utf-8" }, (err, data) => { 
      if (err) { 
        reject(err); 
      } 
      todos = JSON.parse(data); 
      resolve(todos); 
    }); 
  }); 
};

Die readTodos-Methode gibt ein Promise zurück, in dem die Todos aus der data.json-Datei gelesen werden. Das habe ich früher auch gemacht, aber jetzt speichere ich meine To-Dos, die ich aus der Datei auslese, in einem "Todos"-Array. Dieses gleiche Array wird schließlich später benötigt, wenn ich ein Todo hinzufügen und speichern möchte.
Die readTodos-Methode muss in unserer app.js-Datei zur Verfügung gestellt werden, und nach und nach werden wir den GET-Todos-Handler überarbeiten.

const { addTodo, readTodos } = require("../utils/crud.js"); 
const { validator } = require("../utils/validator.js"); 
const express = require("express"); 
const server = express(); 
server.use(express.json()); 
server.get("/todos", async (req, res) => { 
  try { 
    let todos = await readTodos(); 
    res.status(200).send(todos); 
  } catch (error) { 
    res.status(400).send(error); 
  } 
});

Wie in der POST-Anforderung benutze ich async await für sauberen Code, und die aufgelösten Todos werden an den Client zurückgeschickt. Speichere die Datei, und mache eine GET-Anfrage vom Postman, und du solltest die untenstehenden Ergebnisse wieder auf dem Bildschirm erhalten.

[ 
  "Do a good run at the park" 
]

DELETE Request

Wie der Name schon sagt, wird ein Delete Request verwendet, um Daten vom Server zu entfernen. Sobald wir To-Dos hinzufügen und sie lesen können, sollten wir in der Lage sein, ein To-Do bei Bedarf zu löschen. Deshalb werden wir eine "deleteTodo" Methode in unserer Datei crud.js erstellen.

const deleteTodo = (id) => {
  todos.splice(id, 1);
  console.log(todos);
  return new Promise((resolve, reject) => {
    fs.writeFile("./data/data.json", JSON.stringify(todos), (err) => {
      if (err) {
        reject(err);
      }
      resolve();
    });
  });
};

Die "deleteTodo" Methode benutzt die ID des zu löschenden Todos. Zuerst benutze ich die Spleißmethode auf dem Todo-Array, um den bezeichneten Todo-Item zu entfernen, dann wird in dem zurückgegebenen Promise das aktualisierte Todo-Array in unsere Datei geschrieben.
In unserer app.js werden wir etwas zusätzlichen Code benötigen, um den DELETE Request zu bearbeiten;

server.delete("/todo/:id", async (req, res) => {
  try {
    let id = req.params.id;
    await deleteTodo(id);
    res.status(200).send("Todo deleted successfully with id: " + id);
  } catch (error) {
    res.status(400).send(error);
  }
});

Beachte, dass im Delete Request mein Pfad als "/todo/:id" bezeichnet wird. Der Doppelpunkt nach dem Todo/ hat eine besondere Bedeutung und erklärt deutlich, dass die erwartete Benutzereingabe ein Parameter ist. Sagen wir "/todo/5", um Todo mit der ID 5 zu löschen; der Doppelpunkt im Pfad gibt uns Zugriff auf eine neue Eigenschaft des Anfrageobjekts namens "params", die ich hier benutze.
Um mehr über Request-Objekte zu lesen, gehe zur Express-API-Referenz, die hier zu finden ist. Inzwischen sollte der obige Code ziemlich selbsterklärend sein.
Wir rufen die Methode "deleteTodo" aus unserer Datei crud.js auf und übergeben die zerstörte ID, die wir unbedingt löschen wollen. Schließlich geben wir eine Erfolgs- oder Fehlermeldung an den Benutzer zurück.

Wenn der gesamte Code vorhanden ist, teste diesen Endpunkt mit Postman.
Nutze localhost:4000/todo/0 um den ersten Todo zu löschen, den ich erstellt habe. Was du als Output erwarten würdest:
Todo deleted successfully with id: 0

Abschließende Worte

Node.js bietet Entwicklern eine Möglichkeit, serverseitige Applikationen mit minimaler Konfiguration und minimalem Code zu erstellen. Die Verwendung von JavaScript sowohl für das Front-End als auch für das Back-End beschleunigt die Entwicklung von Applikationen. Node.js ist eine ausgezeichnete Wahl für agile Entwicklung und Prototyping. Node wurde entwickelt, um skalierbare I/O-intensive Netzwerkanwendungen zu erstellen. Wie immer gibt es ein "aber": benutze es besser nicht für CPU-intensive Aufgaben.

Autor

Stanimira Yovcheva | Junior Software Engineer

Stanimira is a young professional looking to leave a memorable mark in the IT industry. Her endless thirst for knowledge and her focused approach to technical challenges make her a reliable engineer and a valuable team member. She converts every free minute around work sessions to study advanced software development principles and cool advanced tech, continually looking to put what she learned into good use.