Content
Komplexeres Beispiel Jokewebservice
Für den Jokewebservice kann einfach das Minimalbeispiel erweitert werden.
Der Jokewebservice findet sich in kompletter Ausführung hier: Joke Webservice
NPM
Npm ist der node package manager. Mit dem Befehl npm install [Packetname]
kann ein node.js Modul installiert werden.
package.json
Um die Abhängigkeiten des Projekts zu speichern muss die Datei package.json mit npm init
erstellt werden. Es sind noch zusätzliche Metadaten wie z.b.: App Version, Beschreibung, uws. enthalten.
Alle nach der initialisierung installierten Module werden in der Date package.json mit Versionscode abgespeichert.
Wird nun das Projekt neu ausgecheckt werden alle Abhängigkeiten mit npm install
installiert.
Express
npm install express
Express ist ein Webservice Router, http requests werden an die entsprechenden Routen weitergeleitet.
GET/DELETE/PUT/POST Methoden mit Express
app.get('/', function(req, res) { res.send("Get request"); });
app.delete('/', function(req, res) { res.send("Delete request"); });
app.put('/', function(req, res) { res.send("Put request"); });
app.post('/', function(req, res) { res.send("Post request"); });
CURL Befehle:
curl localhost:3000
#put
curl -X PUT localhost:3000
#put
curl -X DELETE localhost:3000
#put
curl -X POST localhost:3000
Nodemon
npm install -g nodemon
Mit nodemon kann ein node.js Programm gestartet werden. Wird die gestartete Datei verändert, lädt nodemon diese automatisch neu.
Mongoose
Mongoose ist ein Framework um Schemas für MongoDB zu erstellen. Es inkludiert Abfragen, Validierung,...und natürlich die Verbindung zur Datenbank
npm install mongoose
Anbindung der Datenbank in app.js
//Mongoose modul importieren
var mongoose = require('mongoose');
//Verbinden mit Datenbank
mongoose.connect('mongodb://testuser:testpwd@mongodb.drlue.at:9000/testdb?ssl=true&authMechnism=DEFAULT&authSource=authdb');
//Datenbankverbindung holen
var db = mongoose.connection;
//Fehlerausgabe
db.on('error', console.error.bind(console, "MongoDB connection error:"));
//Ausgabe bei erfolgreicher Verbindung
db.once('open', () => {
console.log("Connected...");
});
Beispiel Schema (model/joke.js)
const mongoose = require('mongoose');
const schema = mongoose.Schema;
var jokeSchema = new schema({
text: { type: String },
author: { type: String },
created_at: { type: Date, default: Date.now }
});
//Export the schema
module.exports = mongoose.model('Joke', jokeSchema);
Erstellen/Löschen von Einträgen in der Datenbank app.js
//Schema importieren
var Joke = require('model/joke');
app.get('/', function (req, res) {
//Alle Einträge zurückgeben
Joke.find({})
.then((jokes) => {
res.json(jokes);
})
.catch((error) => {
res.send("FEHLER: " + error.msg);
})
});
//Eintrag anhand der ID löschen
app.get('/:id/delete', function (req, res) {
Joke.findOneAndDelete({ _id: req.params.id })
.then((result) => {
res.send("Deleted");
})
.catch((error) => {
res.send("FEHLER: " + error.msg);
});
});
Mustache
npm install mustache-express
Mustache ist ein template rendering engine. Wir schreiben HTML Code, und können dort Platzhalter einfügen.
views/jokes.mustache
{{#jokes}}
<div class="badge badge-info">{{author}}</div> - {{text}}
{{/jokes}}
Verwenden des Templates in app.js
var mustacheExpress = require('mustache-express');
app.set('views', './views/');
app.set('view engine', 'mustache');
app.engine('mustache', mustacheExpress());
app.get('/', function (req, res) {
Joke.find({})
.then((jokes) => {
//Hier wird das Template joke.mustache verwendet
//Wenn im Template Parameter benötigt werden, so werden diese als JSON übergeben
res.render('joke', { jokes: jokes });
}).catch((error) => {
res.send("FEHLER: " + error.msg);
})
});
Neuen Joke eintragen
Jokes sollen nun über eine HTML Webseite und auch direkt, z.b.: mit curl eingetragen werden können. Um je nach Client Anwendung unterschiedliche Aktionen auszuführen, müssen die Clients die entsprechenden Header mitsenden. Werden Daten nur geholt, so ist der Accept Header wichtig. Dieser beschreibt was der Client gerne hätte:
#Ich möchte eine Webseite
Accept: text/html
#Ich möchte JSON
Accept: application/json
Werden Daten gesendet, so ist der Content-Type Header wichtig. Dieser beschreibt in welchem Format der Client seine Daten sendet:
#Browser sendet Textdaten von einem Formular
Content-Type: x-www-form-urlencoded
#Senden von JSON Daten über eine Anwendung
Content-Type: application/json
Um Daten von POST oder PUT Requests zu erhalten muss folgendes in app.js nach der initialisierung von express() eingetragen werden. Nach dem eintragen kann auf die Werte in gleicherweise zugegriffen werden (egal ob Daten vom Browser oder von einer Anwendung):
//Aktiviert Content-Type: x-www-form-urlencoded
app.use(express.urlencoded());
////Aktiviert Content-Type: application/json
app.use(express.json());
Mustache Datei für das Formular views/joke_create.mustache:
...
<form action="/" id="person" method="post">
<label class="h2" form="person">Erstellung eines Witzes</label>
<label for="vorname">Name des Autoren</label>
<input type="text" name="vorname" id="vorname">
<label for="text">Eingabe des Jokes</label>
<input type="text" name="text" id="text">
<button type="submit">Eingaben absenden</button>
</form>
...
Neue Routen in app.js
//Route für das Formular
app.get('/create', function(req, res) {
res.render("joke_create");
});
//Route für das Eintragen
app.post('/', function (req, res) {
Joke.create({ text: req.body.text, author: req.body.author })
.then((result) => {
if (req.accepts('text/html')) {
res.redirect('/'); //Aufruf von Browser
} else {
res.json(result); //Aufruf von jemandem der kein text/html akzeptiert
}
})
.catch((error) => {
if (req.accepts('text/html')) {
res.redirect('/'); //Aufruf von Browser
} else {
res.json({ error: "could not create joke" }); //Aufruf von jemandem der kein text/html akzeptiert
}
});
});
Einen Witz über curl eintragen
curl -H "Accept: application/json" -H "Content-Type: application/json" -d '{ "author": "lukas", "text": "das ist ein witz" }' -X POST localhost:3000/
Editieren eines Witzes
Neues Mustache file editjoke.mustache
Achtung {{[value]}}
kommt aus dem JSON das dem renderer übergeben wurde.
<form action="/{{_id}}" method="post">
<label class="h2 breit" form="person">Ändern eines Witzes</label><br><br>
<label for="lName">Name des Autoren:</label>
<input type="Author" name="author" id="author" value="{{author}}"><br>
<label for="lWitz">Eingabe des Jokes:</label>
<input class="breit" type="Text" name="text" id="text" value="{{text}}"><br><br>
<button type="submit">Änderung absenden</button>
</form>
Neue Route in app.js
Die Werte aus dem Formular beziehen sich auf den name des Html Elements.
app.post('/:id', function (req, res) {
Joke.findByIdAndUpdate(req.params.id, { author: req.body.author, text: req.body.text })
.then((result) => {
if (req.accepts('text/html')) {
res.redirect('/');
} else {
res.json(result);
}
}).catch((error) => {
if (req.accepts('text/html')) {
res.redirect('/');
} else {
res.json({ error: "could not create joke" });
}
});
});
```
## Joke löschen über Javascript **fetch** api
**views/joke.mustache**
Der Joke wird über die Fetch Api gelöscht, es entsteht kein neuer Seitenaufruf. Wurde der Witz erfolgreich gelöscht, so wird das Html Element aus dem DOM (Document Object Model) entfernt.
```html
<script>
var del = (id) => {
fetch(id,{
method: 'delete'
})
.then(function (result) {
if(result.status == 200){
window.alert("Ok")
document.getElementById(id).remove()
} else if(result.status == 500){
window.alert("Interner Serverfehler")
} else {
window.alert("Could not been found")
}
console.log(result);
})
.catch(function (error) {
console.log(error);
})
}
</script>
...
<a class= "btn-inline btn btn-danger btn-sm" onclick="del('{{_id}}')">Delete</a>
...
Neue Route in app.js
Diese entspricht bis auf den Pfad der get :id/delete Route.
//Delete joke
app.delete('/:id', function (req, res) {
Joke.findOneAndDelete({ _id: req.params.id })
.then((result) => {
if (result == null) {
//Joke wurde nicht gefunden
res.sendStatus(404);
} else {
//Joke wurde erfolgreich gelöscht
res.sendStatus(200);
}
console.log("Successfully deleted...");
})
.catch((error) => {
console.log("Failes to delete...");
res.sendStatus(500);
})
});