refactor: remove outdated server design documentation
Remove 557-line server-design.md from _go-learning/architecture - content is now covered in updated architecture documentation with real implementation examples and test coverage.
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
# Middleware Chain Diagram
|
||||
|
||||
## Middleware Execution Order
|
||||
|
||||
```
|
||||
HTTP Request
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ MIDDLEWARE CHAIN │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ 1. Recovery Middleware │ │
|
||||
│ │ - Catches panics │ │
|
||||
│ │ - Logs stack trace │ │
|
||||
│ │ - Returns 500 error │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ 2. Logger Middleware │ │
|
||||
│ │ - Logs request method, path, IP │ │
|
||||
│ │ - Measures request duration │ │
|
||||
│ │ - Logs response status │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ 3. SecurityHeaders Middleware │ │
|
||||
│ │ - Sets CSP header │ │
|
||||
│ │ - Sets X-Frame-Options │ │
|
||||
│ │ - Sets X-Content-Type-Options │ │
|
||||
│ │ - Sets Referrer-Policy │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ 4. PreferencesMiddleware │ │
|
||||
│ │ - Reads preference cookies │ │
|
||||
│ │ - Migrates old values │ │
|
||||
│ │ - Stores in request context │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└───────────────────────────┼────────────────────────────────┘
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ Router │
|
||||
│ (ServeMux) │
|
||||
└───────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ Handler │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
## Detailed Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Request Processing Flow │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Client Request: GET /?lang=es
|
||||
│
|
||||
▼
|
||||
╔═══════════════════════════════════════════════════════════╗
|
||||
║ RECOVERY MIDDLEWARE ║
|
||||
╠═══════════════════════════════════════════════════════════╣
|
||||
║ defer func() { ║
|
||||
║ if err := recover(); err != nil { ║
|
||||
║ log error + stack trace ║
|
||||
║ http.Error(w, "Internal Server Error", 500) ║
|
||||
║ } ║
|
||||
║ }() ║
|
||||
║ ║
|
||||
║ next.ServeHTTP(w, r) ────────────────┐ ║
|
||||
╚════════════════════════════════════════│══════════════════╝
|
||||
│
|
||||
▼
|
||||
╔═══════════════════════════════════════════════════════════╗
|
||||
║ LOGGER MIDDLEWARE ║
|
||||
╠═══════════════════════════════════════════════════════════╣
|
||||
║ start := time.Now() ║
|
||||
║ log.Printf("[%s] %s %s", r.Method, r.URL.Path, r.RemoteAddr) ║
|
||||
║ ║
|
||||
║ wrapped := responseWriter wrapper ║
|
||||
║ next.ServeHTTP(wrapped, r) ──────────┐ ║
|
||||
║ │ ║
|
||||
║ duration := time.Since(start) │ ║
|
||||
║ log.Printf("Completed in %v (status: %d)", duration, status) ║
|
||||
╚═════════════════════════════════════════│════════════════╝
|
||||
│
|
||||
▼
|
||||
╔═══════════════════════════════════════════════════════════╗
|
||||
║ SECURITY HEADERS MIDDLEWARE ║
|
||||
╠═══════════════════════════════════════════════════════════╣
|
||||
║ w.Header().Set("Content-Security-Policy", CSP_POLICY) ║
|
||||
║ w.Header().Set("X-Frame-Options", "DENY") ║
|
||||
║ w.Header().Set("X-Content-Type-Options", "nosniff") ║
|
||||
║ w.Header().Set("Referrer-Policy", "strict-origin") ║
|
||||
║ ║
|
||||
║ next.ServeHTTP(w, r) ────────────────┐ ║
|
||||
╚════════════════════════════════════════│══════════════════╝
|
||||
│
|
||||
▼
|
||||
╔═══════════════════════════════════════════════════════════╗
|
||||
║ PREFERENCES MIDDLEWARE ║
|
||||
╠═══════════════════════════════════════════════════════════╣
|
||||
║ // Read cookies ║
|
||||
║ prefs := &Preferences{ ║
|
||||
║ CVLength: getCookie(r, "cv-length", "short"), ║
|
||||
║ CVIcons: getCookie(r, "cv-icons", "show"), ║
|
||||
║ CVLanguage: getCookie(r, "cv-language", "en"), ║
|
||||
║ CVTheme: getCookie(r, "cv-theme", "default"), ║
|
||||
║ ColorTheme: getCookie(r, "color-theme", "light"), ║
|
||||
║ } ║
|
||||
║ ║
|
||||
║ // Migrate old values ║
|
||||
║ if prefs.CVLength == "extended" { ║
|
||||
║ prefs.CVLength = "long" ║
|
||||
║ } ║
|
||||
║ ║
|
||||
║ // Store in context ║
|
||||
║ ctx := context.WithValue(r.Context(), PreferencesKey, prefs) ║
|
||||
║ next.ServeHTTP(w, r.WithContext(ctx)) ───┐ ║
|
||||
╚═════════════════════════════════════════════│════════════╝
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ ROUTER HANDLER │
|
||||
│ │
|
||||
│ Matches route │
|
||||
│ Calls handler │
|
||||
└──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ HANDLER FUNC │
|
||||
│ │
|
||||
│ Processes req │
|
||||
│ Returns resp │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
## Route-Specific Middleware
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Route-Specific Middleware Example │
|
||||
│ (PDF Export Endpoint) │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Global Middleware Chain (all routes)
|
||||
│
|
||||
├─ Recovery
|
||||
├─ Logger
|
||||
├─ SecurityHeaders
|
||||
└─ PreferencesMiddleware
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Router (ServeMux) │
|
||||
│ │
|
||||
│ /export/pdf → pdfHandler (protected) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ Route-Specific Chain │ │
|
||||
│ │ │ │
|
||||
│ │ 1. OriginChecker │ │
|
||||
│ │ └─ Verify same origin│ │
|
||||
│ │ │ │
|
||||
│ │ 2. RateLimiter │ │
|
||||
│ │ └─ 3 req/min per IP │ │
|
||||
│ │ │ │
|
||||
│ │ 3. ExportPDF Handler │ │
|
||||
│ │ └─ Generate PDF │ │
|
||||
│ └───────────────────────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Middleware Wrapping Pattern
|
||||
|
||||
```go
|
||||
// Middleware function signature
|
||||
type Middleware func(http.Handler) http.Handler
|
||||
|
||||
// Wrapping example
|
||||
handler := routes.Setup(cvHandler, healthHandler)
|
||||
// Returns:
|
||||
// Recovery(
|
||||
// Logger(
|
||||
// SecurityHeaders(
|
||||
// PreferencesMiddleware(mux)
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
|
||||
// Execution flow (unwraps from outside to inside):
|
||||
Request
|
||||
↓ enters Recovery
|
||||
↓ enters Logger
|
||||
↓ enters SecurityHeaders
|
||||
↓ enters PreferencesMiddleware
|
||||
↓ enters mux/handler
|
||||
↓ handler processes
|
||||
↑ exits PreferencesMiddleware
|
||||
↑ exits SecurityHeaders
|
||||
↑ exits Logger (logs duration)
|
||||
↑ exits Recovery
|
||||
↑
|
||||
Response
|
||||
```
|
||||
|
||||
## Context Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Context Values Through Middleware │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Initial Request Context
|
||||
│
|
||||
├─ Empty context.Background()
|
||||
│
|
||||
▼
|
||||
PreferencesMiddleware
|
||||
│
|
||||
├─ Reads cookies
|
||||
├─ Creates Preferences struct
|
||||
└─ Adds to context
|
||||
│
|
||||
└─→ ctx = context.WithValue(r.Context(), PreferencesKey, prefs)
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ Modified Request Context │
|
||||
│ │
|
||||
│ PreferencesKey → &Preferences{ │
|
||||
│ CVLength: "long", │
|
||||
│ CVIcons: "show", │
|
||||
│ CVLanguage: "es", │
|
||||
│ CVTheme: "default", │
|
||||
│ ColorTheme: "light", │
|
||||
│ } │
|
||||
└──────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
Handler receives request with enriched context
|
||||
│
|
||||
├─→ prefs := middleware.GetPreferences(r)
|
||||
│ // Retrieves from context
|
||||
│
|
||||
└─→ lang := middleware.GetLanguage(r)
|
||||
// Helper that calls GetPreferences
|
||||
```
|
||||
|
||||
## Error Handling in Middleware
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ Error Handling Flow │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
|
||||
Recovery Middleware
|
||||
│
|
||||
│ Normal Flow:
|
||||
│ ┌─────────────────────────────────────┐
|
||||
│ │ next.ServeHTTP(w, r) │
|
||||
│ │ ↓ │
|
||||
│ │ Handler processes successfully │
|
||||
│ │ ↓ │
|
||||
│ │ Returns response │
|
||||
│ └─────────────────────────────────────┘
|
||||
│
|
||||
│ Panic Flow:
|
||||
│ ┌─────────────────────────────────────┐
|
||||
│ │ next.ServeHTTP(w, r) │
|
||||
│ │ ↓ │
|
||||
│ │ Handler panics! │
|
||||
│ │ ↓ │
|
||||
│ │ defer recover() catches it │
|
||||
│ │ ↓ │
|
||||
│ │ log.Printf("PANIC: %v\\n%s", │
|
||||
│ │ err, debug.Stack()) │
|
||||
│ │ ↓ │
|
||||
│ │ http.Error(w, "Internal Error", 500)│
|
||||
│ └─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
Response to client
|
||||
```
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
```
|
||||
Middleware Performance Impact (per request):
|
||||
|
||||
Recovery: ~10 ns (defer overhead)
|
||||
Logger: ~100 μs (time measurements, string formatting)
|
||||
SecurityHeaders: ~50 ns (header setting)
|
||||
Preferences: ~200 μs (cookie parsing, context creation)
|
||||
|
||||
Total overhead: ~350 μs per request
|
||||
Handler time: ~1-5 ms (template rendering)
|
||||
|
||||
Total request: ~1.5-5.5 ms
|
||||
```
|
||||
|
||||
## Related Diagrams
|
||||
|
||||
- [System Architecture](./01-system-architecture.md) - Overall system design
|
||||
- [Request Flow](./02-request-flow.md) - Complete HTTP request lifecycle
|
||||
- [Error Handling](./06-error-handling-flow.md) - Error propagation
|
||||
Reference in New Issue
Block a user