136 lines
4.2 KiB
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.")
|
|
}
|