HTTP: принять задание и показать результат
От функции к серверу
Сервер — запущенная программа, которая принимает запросы и отправляет ответы. HTTP задаёт форму этих сообщений: метод, путь, заголовки и тело. POST /jobs создаёт новое задание, GET /jobs/{id} читает существующее. Тело JSON — текст с именованными полями; сервер должен разобрать его и проверить до изменения состояния.
В этом этапе храните задания в памяти одного процесса. Модель задания содержит id, исходный text, status, result, attempts, error. Возможные состояния: queued — ожидает, running — выполняется, done — успешно завершено, failed — завершилось ошибкой. Настоящий фон и границы параллелизма появятся в следующем этапе. Пока обработка может быть последовательной: не делайте долгую работу внутри HTTP-обработчика окончательной архитектурой.
Что прочитать
Нужны структуры, map, ошибки и тесты из основ Go. Прочитайте из чего состоит приложение и HTTP и договор API. Перед практикой разберите net/http, encoding/json, http.Handler, http.ResponseWriter и *http.Request: ServeHTTP получает запрос и записывает статус, заголовки и тело ответа. В тестах httptest.NewRequest создаёт запрос без сети, а httptest.NewRecorder сохраняет ответ обработчика. Их роль — проверить ваш API без свободного порта и отдельного процесса.
Реализуйте договор
Найдите New(Config) и HTTP-обработчик приложения в стартовом проекте. New возвращает приложение или ошибку подготовки. Добавьте создание задания и чтение по id. Успешный POST получает JSON {"text":"hello go"} и возвращает 202 с записью задания. К моменту чтения результат может ещё отсутствовать: 202 сообщает о принятии, а не гарантирует done.
Для неизвестного id верните 404. Неверный JSON, отсутствующее поле text, значение другого типа и текст, пустой после удаления краевых пробелов, получают 400. На первом этапе функция Analyze принимала пустую строку; API сознательно задаёт более узкий допустимый вход. Неподдерживаемый метод также не должен давать успешное создание. Если вы уже начали записывать тело ответа, поздно менять его статус; задавайте заголовки и статус до тела.
В ServeHTTP метод доступен как r.Method, путь — как r.URL.Path, а тело — как r.Body. Тело читается последовательно; для JSON нужен декодер, который читает его поток. Вот отдельная функция разбора входа. Поместите её вне main и вне ServeHTTP; подключите encoding/json, errors, net/http и strings:
func readText(r *http.Request) (string, error) {
var input struct {
Text string `json:"text"`
}
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
return "", err
}
if strings.TrimSpace(input.Text) == "" {
return "", errors.New("text must not be empty")
}
return input.Text, nil
}&input позволяет декодеру заполнить структуру. Функция сохраняет исходный текст: это понадобится для ключа повторного запроса. Вы сами добавляете вызов в обработчик, запись задания и ответ. Для записи JSON подключите encoding/json, задайте w.Header().Set("Content-Type", "application/json"), затем статус через w.WriteHeader и кодирование записи через json.NewEncoder(w).Encode. Ошибку кодирования тоже обработайте: повторно отправить другой статус после записи ответа уже нельзя.
Для самостоятельного теста создайте запрос и вызовите приложение через httptest. Фрагмент размещается внутри функции TestStage02... файла _test.go; app здесь — уже созданное приложение. Подключите net/http/httptest, net/http и strings:
request := httptest.NewRequest(http.MethodPost, "/jobs", strings.NewReader(`{"text":"hello go"}`))
recorder := httptest.NewRecorder()
app.ServeHTTP(recorder, request)Проверьте recorder.Code и JSON в recorder.Body.Bytes(). Такой тест вызывает реальный обработчик, но не поднимает сервер на порту. Создание приложения и его остановку после теста вы добавляете по публичным методам из каркаса.
Запустите сервер:
go run ./cmd/serverПо умолчанию он слушает 127.0.0.1:8080. 127.0.0.1 означает этот компьютер. Оставьте сервер в первом терминале; во втором отправьте запросы. В PowerShell используйте curl.exe, чтобы вызвать именно curl:
curl -i -X POST http://127.0.0.1:8080/jobs -H 'Content-Type: application/json' -d '{"text":"hello go"}'
curl -i http://127.0.0.1:8080/jobs/IDЗамените ID номером из ответа. Если curl недоступен, проверяйте API через httptest и включённый в проект локальный клиент нагрузки на последнем этапе. Пример JSON здесь записан для оболочек с одинарными кавычками; в PowerShell при проблемах с кавычками сохраните тело в файл и передайте --data-binary @request.json.
Проверьте API
go test ./... -run '^TestStage0[12]' -count=1Дополните свой тест: создайте задание, извлеките id из JSON-ответа, прочитайте его; затем запросите неизвестный id. Проверьте статус и поля, а не только отсутствие ошибки. Объясните, почему повтор одного POST пока создаёт второе задание. Защита от повторов появится на пятом этапе.
Типичные ошибки: отдавать 200 на любое обращение; писать JSON с помощью склейки строк; принимать сломанный JSON как пустой текст; считать id результатом вычисления; запускать два сервера на одном порту. После остановки и нового запуска данные в памяти пропадают — это ожидаемое ограничение текущего этапа.
Когда идти дальше
Покажите успешный запрос, неверный JSON и неизвестный id. Проследите один запрос от метода и пути до записи в памяти и ответа. Автотест проверяет договор, но объяснение последовательности остаётся вашей задачей. Дальше перенесём обработку в ограниченный пул.
Самопроверка этапа
Отмечайте результат после своей проверки. Открытие главы ничего не завершает. Отметки сохраняются в этом браузере и не являются независимой аттестацией.
Для завершения отметьте все критерии и добавьте объяснение.