- Einrichtung des Projekts
- Der Server in seiner Grundstruktur
- Die Kundendaten im Hauptspeicher
- Die Anfragen per Curl
- Ablegen der Daten in einer Datenbank
Einrichtung des Projekts
Für das einfachere Routing wird Express eingesetzt. Also beginnen alle Aktivitäten mit der Einrichtung des Projekts.
mkdir rest cd rest npm init npm install express
Der Server in seiner Grundstruktur
const { request, response } = require("express"); const express = require("express"); const PORT = 8080; const HOST = "localhost"; const app = express(); app.use(express.json()); const KundenData = require("./KundenData"); const kundenData = new KundenData(); app.get("/rest/kunden", async function(request, response) { const kunden = await kundenData.getKunden(); kunden.forEach( function(kunde) { kunde.href = "rest/kunden/"+kunde.id; }); response.status(200).send(kunden); }); app.get("/rest/kunden/:id", async function(request, response) { const id = parseInt(request.params.id); const kunde = kundenData.getKunde(id); if (kunde) { response.status(200).send(kunde); } else { response.status(404).send(); } }); app.post("/rest/kunden", async function(request, response) { const kunde = request.body; const id = await kundenData.addKunde(kunde); kunde.href = "/rest/kunden/"+id; response.status(200).location("/rest/kunden/"+id).send(kunde); }); app.put("/rest/kunden/:id", async function(request, response) { const id = parseInt(request.params.id); const kunde = request.body; await kundenData.updateKunde(id, kunde); response.status(200).send(); }); app.delete("/rest/kunden/:id", async function(request, response) { const id = parseInt(request.params.id); await kundenData.deleteKunde(id); response.status(200).send(); }); const server = app.listen(PORT, function() { console.log("Server running http://"+HOST+":"+PORT); });
Die Kundendaten im Hauptspeicher
Die Kundendaten werden in der ersten Form nur in einer Map und damit im Hauptspeicher abgelegt und gehen damit bei Neustart des Servers verloren.Es wird eine Klasse KundenData angelegt. Mit addKunde, updateKunde, deleteKunde und den Get-Funktionen werden alle Aktivitäten realisiert, die für einen Kunden infrage kommen.
class KundenData { constructor() { this.kundenMap = new Map(); this.counter = 0; } async addKunde(kunde) { console.log("addKunde"); this.counter++; kunde.id = this.counter; this.kundenMap.set(this.counter, kunde); return this.counter; } async getKunde(id) { return this.kundenMap.get(id); } async updateKunde(id, kunde) { kunde.id = id; this.kundenMap.set(id, kunde); } async deleteKunde(id) { this.kundenMap.delete(id); } async getKunden() { return Array.from(this.kundenMap.values()); } }; module.exports = KundenData
Die Anfragen per Curl
Mit dem folgenden Curl-Befehl wird ein POST an den Server geschickt. Im Gepäck ist die JSON-Darstellung eines Kunden. Als Ergebnis liefert der Server die URL, unter der der Kunde zugreifbar ist.
curl -v --header "Content-Type: application/json" --request POST \ --data '{"name":"Anton", "adresse":"Holzweg", "tel":"5014"}' \ http://localhost:8080/rest/kundenMit einem GET auf die API wird eine Liste aller Kunden ausgegeben.
curl -v http://localhost:8080/rest/kundenDer Befehl PUT wird einen bestimmten Kunden (hier Kunde Nummer 2) mit neuen Daten versehen.
curl -v --header "Content-Type: application/json" --request PUT \\ --data '{"name":"Anton", "adresse":"Holzweg", "tel":"5014"}' \\ http://localhost:8080/rest/kunden/2Zu guter Letzt kann ein Kunde auch wieder entfernt werden. Auch hier muss die ID in der URL angegeben werden.
curl -v --header "Content-Type: application/json" --request DELETE http://localhost:8080/rest/kunden/1
Ablegen der Daten in einer Datenbank
Die Daten eines REST-Servers sollten natürlich gern den nächsten Stromausfall oder den Neustart des Servers überleben. Dazu ist es sinnvoll, eine Datenbank zu hinterlegen.Die REST-Struktur nimmt die HTTP-Befehle GET, POST, PUT und DELETE auf und übersetzt sie in die Datenbankaufrufe SELECT, INSERT, UPDATE und DELETE.
Das folgende Listing verwendet die Datenbank sqlite3 für die Speicherung der Daten. Ohne großen Aufwand könnte natürlich auch eine große Datenbank wie PostgreSQL verwendet werden.
const sqlite3 = require("sqlite3"); const db = new sqlite3.Database("kunden.db"); class KundenSQL { constructor() { db.run( `CREATE TABLE IF NOT EXISTS kunden ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, adresse TEXT, email TEXT )` ); } async addKunde(kunde) { console.log("addKunde"); return new Promise( function(resolve, reject) { db.run( "INSERT INTO kunden (name, adresse, email) VALUES (?, ?, ?)", [kunde.name, kunde.adresse, kunde.email], function () { resolve(this.lastID); } ); }); } async deleteKunde(id) { return new Promise(function(resolve, reject) { db.run("DELETE FROM kunden WHERE id = ?", [id], function(error, row) { if (error) { reject(error); } else { resolve(row); } }); }); } async getKunde(id) { return new Promise( function(resolve, reject) { db.get("SELECT * FROM kunden WHERE id = ?", [id], function(error, row) { if (error) { reject(error); } else { resolve(row); } }); }); } async getKunden() { return new Promise(function(resolve, reject) { db.all("SELECT * FROM kunden", [], function(error, rows) { if (error) { reject(error); } else { resolve(rows); } }); }); } }; module.exports = KundenSQL