package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"sync"
"time"
)
// ============================================
// Models
// ============================================
type User struct {
ID int `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
}
type CreateUserRequest struct {
Email string `json:"email"`
Name string `json:"name"`
}
type APIResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}
// ============================================
// Database (Thread-Safe In-Memory)
// ============================================
type Database struct {
users map[int]*User
nextID int
mu sync.RWMutex
}
func NewDatabase() *Database {
return &Database{
users: make(map[int]*User),
nextID: 1,
}
}
func (db *Database) CreateUser(req CreateUserRequest) *User {
db.mu.Lock()
defer db.mu.Unlock()
user := &User{
ID: db.nextID,
Email: req.Email,
Name: req.Name,
CreatedAt: time.Now(),
}
db.users[db.nextID] = user
db.nextID++
return user
}
func (db *Database) GetUser(id int) *User {
db.mu.RLock()
defer db.mu.RUnlock()
return db.users[id]
}
func (db *Database) GetAllUsers() []*User {
db.mu.RLock()
defer db.mu.RUnlock()
users := make([]*User, 0, len(db.users))
for _, user := range db.users {
users = append(users, user)
}
return users
}
func (db *Database) DeleteUser(id int) bool {
db.mu.Lock()
defer db.mu.Unlock()
if _, exists := db.users[id]; exists {
delete(db.users, id)
return true
}
return false
}
// ============================================
// Middleware
// ============================================
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("[%s] %s %s", r.Method, r.URL.Path, time.Since(start))
})
}
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
// ============================================
// Handlers
// ============================================
var db = NewDatabase()
func respondJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
respondJSON(w, http.StatusOK, map[string]string{
"status": "healthy",
"timestamp": time.Now().Format(time.RFC3339),
})
}
func getUsersHandler(w http.ResponseWriter, r *http.Request) {
users := db.GetAllUsers()
respondJSON(w, http.StatusOK, APIResponse{Success: true, Data: users})
}
func createUserHandler(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
respondJSON(w, http.StatusBadRequest, APIResponse{Error: "Invalid JSON"})
return
}
if req.Email == "" || req.Name == "" {
respondJSON(w, http.StatusBadRequest, APIResponse{Error: "Email and name required"})
return
}
user := db.CreateUser(req)
respondJSON(w, http.StatusCreated, APIResponse{Success: true, Data: user})
}
func getUserHandler(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
respondJSON(w, http.StatusBadRequest, APIResponse{Error: "Invalid ID"})
return
}
user := db.GetUser(id)
if user == nil {
respondJSON(w, http.StatusNotFound, APIResponse{Error: "User not found"})
return
}
respondJSON(w, http.StatusOK, APIResponse{Success: true, Data: user})
}
func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
respondJSON(w, http.StatusBadRequest, APIResponse{Error: "Invalid ID"})
return
}
if !db.DeleteUser(id) {
respondJSON(w, http.StatusNotFound, APIResponse{Error: "User not found"})
return
}
w.WriteHeader(http.StatusNoContent)
}
// ============================================
// Main
// ============================================
func main() {
mux := http.NewServeMux()
// Routes (Go 1.22+ path patterns)
mux.HandleFunc("GET /health", healthHandler)
mux.HandleFunc("GET /api/users", getUsersHandler)
mux.HandleFunc("POST /api/users", createUserHandler)
mux.HandleFunc("GET /api/users/{id}", getUserHandler)
mux.HandleFunc("DELETE /api/users/{id}", deleteUserHandler)
// Apply middleware
handler := loggingMiddleware(corsMiddleware(mux))
log.Println("Server running on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", handler))
}