273 lines
5.3 KiB
Markdown
273 lines
5.3 KiB
Markdown
# 6.3 Backend-Entwicklung
|
|
|
|
## Server-Grundlagen
|
|
|
|
### Client-Server-Architektur
|
|
|
|
```
|
|
Webanwendung - Architektur
|
|
┌─────────────┐ HTTP ┌─────────────┐
|
|
│ Browser │ ◄──────────────►│ Server │
|
|
│ (Frontend) │ │ (Backend) │
|
|
└─────────────┘ └──────┬──────┘
|
|
│
|
|
┌─────┴─────┐
|
|
│ Datenbank │
|
|
└───────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Node.js
|
|
|
|
### Grundlagen
|
|
|
|
```javascript
|
|
// Einfacher Server
|
|
const http = require('http');
|
|
|
|
const server = http.createServer((req, res) => {
|
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
res.end('<h1>Hallo Welt!</h1>');
|
|
});
|
|
|
|
server.listen(3000, () => {
|
|
console.log('Server läuft auf Port 3000');
|
|
});
|
|
```
|
|
|
|
### Express.js
|
|
|
|
```javascript
|
|
const express = require('express');
|
|
const app = express();
|
|
|
|
// Middleware
|
|
app.use(express.json());
|
|
|
|
// GET-Route
|
|
app.get('/api/benutzer', (req, res) => {
|
|
res.json([
|
|
{ id: 1, name: 'Max' },
|
|
{ id: 2, name: 'Anna' }
|
|
]);
|
|
});
|
|
|
|
// POST-Route
|
|
app.post('/api/benutzer', (req, res) => {
|
|
const neuerBenutzer = req.body;
|
|
// Speichern...
|
|
res.status(201).json(neuerBenutzer);
|
|
});
|
|
|
|
app.listen(3000);
|
|
```
|
|
|
|
---
|
|
|
|
## REST-API
|
|
|
|
### REST-Prinzipien
|
|
|
|
```
|
|
REST - Grundsätze
|
|
├── Ressourcen-orientiert (Nomen)
|
|
├── Stateless (keine Session)
|
|
├── Einheitliche Schnittstelle
|
|
├── Client-Server-Trennung
|
|
└── Cache-fähig
|
|
```
|
|
|
|
### HTTP-Methoden
|
|
|
|
| Methode | CRUD | Beschreibung |
|
|
|---------|-----|-------------|
|
|
| GET | Read | Daten abrufen |
|
|
| POST | Create | Daten erstellen |
|
|
| PUT | Update | Daten vollständig ersetzen |
|
|
| PATCH | Update | Daten teilweise ändern |
|
|
| DELETE | Delete | Daten löschen |
|
|
|
|
### API-Endpunkte
|
|
|
|
```
|
|
Beispiel: Benutzer-Ressource
|
|
|
|
GET /api/benutzer → Alle Benutzer
|
|
GET /api/benutzer/:id → Ein Benutzer
|
|
POST /api/benutzer → Benutzer erstellen
|
|
PUT /api/benutzer/:id → Benutzer ersetzen
|
|
PATCH /api/benutzer/:id → Benutzer ändern
|
|
DELETE /api/benutzer/:id → Benutzer löschen
|
|
```
|
|
|
|
### Response-Format
|
|
|
|
```json
|
|
// Erfolgreich (200 OK)
|
|
{
|
|
"status": "success",
|
|
"data": {
|
|
"id": 1,
|
|
"name": "Max"
|
|
}
|
|
}
|
|
|
|
// Erfolg (201 Created)
|
|
{
|
|
"status": "success",
|
|
"message": "Benutzer erstellt",
|
|
"data": {
|
|
"id": 2
|
|
}
|
|
}
|
|
|
|
// Fehler (400 Bad Request)
|
|
{
|
|
"status": "error",
|
|
"message": "Ungültige E-Mail-Adresse"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Datenbank-Zugriff
|
|
|
|
### MySQL mit Node.js
|
|
|
|
```javascript
|
|
const mysql = require('mysql2/promise');
|
|
|
|
async function main() {
|
|
const connection = await mysql.createConnection({
|
|
host: 'localhost',
|
|
user: 'root',
|
|
password: 'passwort',
|
|
database: 'webshop'
|
|
});
|
|
|
|
// Daten abfragen
|
|
const [rows] = await connection.execute(
|
|
'SELECT * FROM benutzer WHERE id = ?',
|
|
[1]
|
|
);
|
|
console.log(rows);
|
|
|
|
await connection.end();
|
|
}
|
|
|
|
main();
|
|
```
|
|
|
|
### MongoDB mit Node.js
|
|
|
|
```javascript
|
|
const mongoose = require('mongoose');
|
|
|
|
// Verbindung
|
|
mongoose.connect('mongodb://localhost:27017/webshop');
|
|
|
|
// Schema
|
|
const benutzerSchema = new mongoose.Schema({
|
|
name: String,
|
|
email: { type: String, unique: true },
|
|
alter: Number
|
|
});
|
|
|
|
const Benutzer = mongoose.model('Benutzer', benutzerSchema);
|
|
|
|
// Daten speichern
|
|
const neuerBenutzer = new Benutzer({
|
|
name: 'Max',
|
|
email: 'max@example.com'
|
|
});
|
|
await neuerBenutzer.save();
|
|
```
|
|
|
|
---
|
|
|
|
## Session und Authentifizierung
|
|
|
|
### JWT (JSON Web Token)
|
|
|
|
```javascript
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
// Token erstellen
|
|
function createToken(user) {
|
|
return jwt.sign(
|
|
{ id: user.id, email: user.email },
|
|
'geheimer-schluessel',
|
|
{ expiresIn: '24h' }
|
|
);
|
|
}
|
|
|
|
// Token prüfen
|
|
function verifyToken(token) {
|
|
try {
|
|
return jwt.verify(token, 'geheimer-schluessel');
|
|
} catch (err) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Middleware
|
|
function authenticate(req, res, next) {
|
|
const token = req.headers.authorization?.split(' ')[1];
|
|
const decoded = verifyToken(token);
|
|
|
|
if (!decoded) {
|
|
return res.status(401).json({ error: 'Nicht autorisiert' });
|
|
}
|
|
|
|
req.user = decoded;
|
|
next();
|
|
}
|
|
```
|
|
|
|
### Passwort-Hashing
|
|
|
|
```javascript
|
|
const bcrypt = require('bcrypt');
|
|
|
|
// Passwort hashen
|
|
async function hashPassword(password) {
|
|
const salt = await bcrypt.genSalt(10);
|
|
return await bcrypt.hash(password, salt);
|
|
}
|
|
|
|
// Passwort prüfen
|
|
async function checkPassword(password, hash) {
|
|
return await bcrypt.compare(password, hash);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## RESTful Best Practices
|
|
|
|
### Tipps
|
|
|
|
```
|
|
API-Design - Empfehlungen
|
|
├── Versionierung: /api/v1/...
|
|
├── Plural: /benutzer nicht /benutzer
|
|
├── Filter: /benutzer?alter=25
|
|
├── Sortierung: /benutzer?sort=name
|
|
├── Paginierung: /benutzer?page=1&limit=10
|
|
├── Fehlercodes: HTTP-Statuscodes nutzen
|
|
└── Dokumentation: OpenAPI/Swagger
|
|
```
|
|
|
|
---
|
|
|
|
## Querverweise
|
|
|
|
- [[LF6-02-Frontend|Zurück: Frontend-Entwicklung]]
|
|
- [[LF6-04-Sicherheit-Web|Nächstes Thema: Web-Sicherheit]]
|
|
- [[LF3-Datenbanken|Datenbanken]]
|
|
|
|
---
|
|
|
|
*Stand: 2024*
|