Материалы / 12 минут
Построить компактный Go API с явной валидацией, единым форматом ошибок и ограниченными таймаутами.
Handler — это граница, а не бизнес-логика
HTTP-handler читает запрос, ограничивает его размер, валидирует форму и вызывает use case. Решения о доступе к данным и правила продукта не должны зависеть от ResponseWriter.
Такая граница позволяет тестировать поведение без запуска сервера и менять транспорт, не переписывая основную логику.
Ошибки являются частью API
Клиенту нужен стабильный код ошибки, безопасное сообщение и request ID. Внутренняя причина остаётся в структурированном логе.
Используйте HTTP-статусы последовательно: 400 для формы запроса, 401 для отсутствующей сессии, 403 для запрещённого действия, 404 для неизвестного ресурса и 409 для конфликта состояния.
- Не возвращайте stack trace или текст SQL-ошибки.
- Ограничивайте тело запроса до декодирования JSON.
- Завершайте внешние операции через context deadline.
Сервер должен уметь останавливаться
Настройте ReadHeaderTimeout, IdleTimeout и graceful shutdown. При остановке новый трафик перестаёт приниматься, а активные запросы получают короткое окно на завершение.
Health endpoint проверяет жизнеспособность процесса, но не должен выполнять тяжёлые запросы к каждой зависимости.
func createProject(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
var input CreateProjectInput
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
writeError(w, http.StatusBadRequest, "invalid_request")
return
}
result, err := projects.Create(r.Context(), input)
writeResult(w, result, err)
}