package api import ( "fmt" "log/slog" "net/http" "time" ) // UserService — интерфейс сервиса пользователей для хендлера. type UserService interface { GetProfile(token string) string } // AuthService — интерфейс сервиса авторизации для хендлера. type AuthService interface { // методы, которые хендлер использует из сервиса авторизации } // NotificationService — интерфейс сервиса уведомлений для хендлера. type NotificationService interface { // методы, которые хендлер использует из сервиса уведомлений } // Handler — интерфейс обработчика HTTP-запросов. type Handler interface { Routes() http.Handler } // handler — конкретная реализация, скрыта от внешних пакетов. // Содержит только хендлеры и роутинг. // Ничего не знает про http.Server, порт или lifecycle — // это ответственность app-слоя. type handler struct { userService UserService authService AuthService notificationService NotificationService } // NewHandler создаёт обработчик HTTP-запросов. func NewHandler( userService UserService, authService AuthService, notificationService NotificationService, ) Handler { return &handler{ userService: userService, authService: authService, notificationService: notificationService, } } // Routes возвращает маршрутизатор со всеми зарегистрированными хендлерами. // App-слой использует этот http.Handler при создании http.Server. func (h *handler) Routes() http.Handler { mux := http.NewServeMux() mux.HandleFunc("GET /health", h.healthHandler) mux.HandleFunc("GET /users/me", h.getUserProfile) // /slow — эндпоинт для демонстрации graceful shutdown. // Имитирует долгий запрос: обращение к БД, вызов внешнего API и т.д. // Пять секунд — чтобы мы успели нажать Ctrl+C, пока запрос выполняется. mux.HandleFunc("GET /slow", h.slowHandler) return mux } func (h *handler) healthHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) if _, err := fmt.Fprintln(w, "ok"); err != nil { slog.Error("ошибка записи ответа", "err", err) } } func (h *handler) getUserProfile(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") profile := h.userService.GetProfile(token) w.WriteHeader(http.StatusOK) if _, err := fmt.Fprintln(w, profile); err != nil { slog.Error("ошибка записи ответа", "err", err) } } // slowHandler — медленный эндпоинт для демонстрации graceful shutdown. // Имитирует реальную работу: запрос в базу, вызов внешнего сервиса. // // Попробуйте: // 1. curl localhost:8080/slow // 2. Пока запрос висит — нажмите Ctrl+C в терминале сервера // 3. Без graceful shutdown: curl получит "connection reset by peer" // 4. С graceful shutdown: curl дождётся и получит "готово!" — 200 OK func (h *handler) slowHandler(w http.ResponseWriter, _ *http.Request) { slog.Info("обрабатываю медленный запрос...") time.Sleep(5 * time.Second) // имитация: запрос в БД, внешний API w.WriteHeader(http.StatusOK) if _, err := fmt.Fprintln(w, "готово!"); err != nil { slog.Error("ошибка записи ответа", "err", err) } }