С чтением данных мы разобрались, давайте теперь попробуем их записывать.
Создание новой записи в нашей телефонной книге через telnet
будет таким:
telnet localhost 4000
Trying ::1...
Connected to localhost.
Escape character is '^]'.
POST /users.json HTTP/1.1
Host: localhost:4000
Connection: close
Content-Type: application/json
Content-Length: 38
{"name":"Bob","phone":"912-114-23-22"}
HTTP/1.1 201 Created
Content-Type: application/json
Date: Sat, 08 Oct 2016 10:23:06 GMT
Connection: keep-alive
Transfer-Encoding: chunked
5c
{"meta":{"location":"/users/15.json"},"data":{"name":"Bob","phone":"912-114-23-22","id":15}}
0
Отметим несколько важных моментов:
Добавлению новых данных в http
соответствует глагол POST
. Такой запрос не
является идемпотентным (в соответствии с семантикой POST
). Это означает, что
повторная отправка данных приведёт к созданию дублей либо к ошибке
(если внутри проверяются дубли).
Почти наверняка вы сталкивались с подобным поведением в интернете. Быстрый
двойной клик на кнопке приводит к тому, что появляется, например, два комментария.
А иногда, когда вы нажимаете f5
, браузер спрашивает "вы точно хотите повторно
отправить данные?". Это означает, что предыдущий запрос был POST
.
Так как в случае POST
запроса мы отправляем тело, нам нужно указать два заголовка:
Content-Type
- чтобы сервер знал, как парсить наше телоContent-Length
- для определения конца запроса
Сервер
import http from 'http';
export default http.createServer((req, res) => {
const body = [];
req
.on('data', chunk => body.push(chunk.toString()))
.on('end', () => {
const data = body.join();
req.end(data);
});
});
С точки зрения сервера body
не является свойством объекта request
,
вместо этого сам request
является eventEmitter
и позволяет подписаться
на событие data
, которое вызывается каждый раз, когда приходит новая порция
данных. Такой подход используется из-за того, что данные можно слать на сервер порциями (chunks).
После того, как запрос был полностью обработан, request
инициирует событие
end
, внутри которого и нужно делать обработку поступивших данных и отвечать
на запрос.
Обратите внимание на то, как идет работа с чанками данных. Перед тем, как попасть
в массив body
, делается преобразование в строку с помощью toString
.
Это связано с тем, что сырой чанк приходит как тип данных Buffer
, который
позволяет работать в том числе с данными в бинарном виде, а не только текстовом.
Валидация
В разработке существует правило: "никогда не доверяй данным из внешнего источника". Это означает, что данные пришедшие извне (от других систем, от пользователя), всегда рассматриваются, как потенциально опасные и не соответствующие требованиям формата этих данных. Если этого не делать, не проверять их, не фильтровать, то легко можно получить ситуацию, при которой вашу систему смогут обойти и, в худшем случае, разрушить или увести данные.
Процесс проверки данных на корректность называется валидацией. В типичных веб-приложениях данные приходят из форм, которые заполняют пользователи или по API, и перед тем, как добавлять их к себе в хранилище, важно провалидировать эти данные. В самой валидации нет ничего сверхъестественного, это обычная проверка в коде, например, на то, что телефон приходит в строго определенном формате.
Ответ
Важно отвечать на POST
запрос правильно, и это зависит от разных факторов.
Выделим три ситуации (хотя, их больше на самом деле):
Успешный запрос (API)
Код ответа 201 (Created)
. В теле ответа обычно возвращают данные, такие как
присвоенный идентификатор, что позволяет обратиться к вновь созданной сущности.
Успешный запрос (Web)
Необходимо обязательно сделать перенаправление (редирект) на другую страницу. Предпочтительно
использовать код 303 (See Other)
.
Ошибка валидации
В этой ситуации код ответа должен быть 422 (unprocessable entity)
в любом случае.
Для разных видов приложения будет различаться только тело и его формат.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты