Files
2026-04-13 08:10:14 +03:00

106 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}