Aufgaben-Python/courses/go/14_json_apis_und_middleware/aufgabe.go

136 lines
4.2 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http"
"sync"
)
// ============================================================================
// 🚀 GO 14: REST JSON APIS & MIDDLEWARE CHAINING
// ============================================================================
// 🎯 TODO 1a: Definiere das Struct 'Device' mit JSON-Tags
// Felder:
// - ID int `json:"id"`
// - Name string `json:"name"`
// - IP string `json:"ip"`
// - Active bool `json:"active"`
type Device struct {
// TODO: Felder mit json-Tags ergänzen
ID int `json:"id"`
Name string `json:"name"`
IP string `json:"ip"`
Active bool `json:"active"`
}
// 🎯 TODO 1b: Definiere das Struct 'APIResponse'
// Felder:
// - Success bool `json:"success"`
// - Message string `json:"message"`
// - Data interface{} `json:"data,omitempty"`
type APIResponse struct {
// TODO: Felder mit json-Tags ergänzen
Success bool `json:"success"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// DeviceStore verwaltet Devices im Speicher
type DeviceStore struct {
mu sync.RWMutex
devices []Device
nextID int
}
func NewDeviceStore() *DeviceStore {
return &DeviceStore{
devices: make([]Device, 0),
nextID: 1,
}
}
// 🎯 TODO 2a: Implementiere 'GetDevicesHandler'
// Gibt alle Devices aus dem Store als JSON mit Status 200 OK zurück.
func (s *DeviceStore) GetDevicesHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, `{"error":"Method not allowed"}`, http.StatusMethodNotAllowed)
return
}
// TODO: Content-Type Header setzen, s.mu.RLock nutzen und s.devices mit json.NewEncoder enkodieren
}
// 🎯 TODO 2b: Implementiere 'CreateDeviceHandler'
// Parst einen neuen Device-Eintrag aus dem JSON-Body.
// Validierung:
// - 'Name' und 'IP' dürfen nicht leer sein (sonst 400 Bad Request mit Fehlermeldung).
// - Bei Erfolg: ID vergeben, an 'devices' anhängen, Status 201 Created und das erstellte Device zurückgeben.
func (s *DeviceStore) CreateDeviceHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, `{"error":"Method not allowed"}`, http.StatusMethodNotAllowed)
return
}
// TODO: JSON decode, validieren, ID zuweisen und antworten
}
// 🎯 TODO 3: Implementiere 'AuthMiddleware'
// Prüft den Request-Header 'X-API-Key'.
// - Wenn r.Header.Get("X-API-Key") != secretKey:
// Setze Content-Type: application/json, Status 401 Unauthorized und antworte mit:
// `{"success":false,"message":"unauthorized"}`
// - Sonst: next.ServeHTTP(w, r)
func AuthMiddleware(secretKey string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// TODO: Header prüfen und delegieren
next.ServeHTTP(w, r)
})
}
}
// 🎯 TODO 4a: Implementiere 'RecoveryMiddleware'
// Fängt Panics im Handler-Baum ab mit 'defer func() { if err := recover(); err != nil ... }()'.
// Bei einer Panic:
// - Schreibe Content-Type: application/json, Status 500 Internal Server Error
// - Body: `{"success":false,"message":"internal server error"}`
func RecoveryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// TODO: defer recover() einbauen und next.ServeHTTP(w, r) aufrufen
next.ServeHTTP(w, r)
})
}
// 🎯 TODO 4b: Implementiere 'ApplyMiddleware'
// Verkettet eine Liste von Middleware-Funktionen um den Handler 'h'.
func ApplyMiddleware(h http.Handler, middlewares ...func(http.Handler) http.Handler) http.Handler {
// TODO: Von rechts nach links um 'h' wrappen
for i := len(middlewares) - 1; i >= 0; i-- {
h = middlewares[i](h)
}
return h
}
func main() {
fmt.Println("=== Go 14: REST JSON APIs & Middleware ===")
store := NewDeviceStore()
mux := http.NewServeMux()
mux.HandleFunc("/api/v1/devices", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
store.GetDevicesHandler(w, r)
} else if r.Method == http.MethodPost {
store.CreateDeviceHandler(w, r)
}
})
handler := ApplyMiddleware(mux,
RecoveryMiddleware,
AuthMiddleware("secret-token-123"),
)
_ = handler
fmt.Println("API-Server mit Auth- und Recovery-Middleware konfiguriert.")
}