Можно ли передавать идентификатор (id) в теле POST-запроса при создании ресурса?

Ответ

Технически — да, но с точки зрения RESTful-архитектуры и семантики HTTP — это противоречивая практика.

Стандартный подход (REST):

  • Метод POST на коллекцию (например, /api/users) предназначен для создания нового ресурса, идентификатор которого должен быть сгенерирован на стороне сервера (часто в БД). Клиент не должен знать или указывать этот id заранее.
  • Успешный ответ 201 Created обычно содержит заголовок Location с URL нового ресурса (например, /api/users/123) и может включать созданный объект в теле.

Пример на Express.js:

app.post('/api/users', async (req, res) => {
  const userData = req.body; // { name: 'Alice', email: 'alice@example.com' }
  // id НЕ ожидается в userData
  const newUser = await db.users.create(userData); // Сервер генерирует id
  res.status(201).location(`/api/users/${newUser.id}`).json(newUser);
});

Когда передача id в POST может иметь смысл (но лучше избегать):

  1. Импорт данных: При массовом импорте существующих данных из другой системы, где id нужно сохранить.
  2. Специфичная бизнес-логика: Если идентификатор является не техническим ключом БД, а частью бизнес-данных (например, артикул товара, который задает клиент).

Альтернативы:

  • Для операций, где клиент определяет ключ ресурса, более семантически верным является метод PUT на конкретный URL (например, PUT /api/users/alices-article-number). PUT идемпотентен и означает «создать или полностью заменить ресурс по данному идентификатору».

В моих проектах на Node.js я строго следую принципам REST: POST для создания без указания id, PUT/PATCH для обновления по известному id. Это делает API предсказуемым и понятным для всех разработчиков.

Ответ 18+ 🔞

А, ну вот это интересный вопрос, прям в точку! Смотри, технически-то твой сервак, конечно, может сожрать POST-запрос с id в теле. Код проглотит, запишет в базу — и вроде бы работает. Но с точки зрения REST, это как заехать в пиццерию и принести с собой свою готовую пиццу, требуя, чтобы её просто разогрели и дали тебе чек. Ну то есть странно, ёпта.

Каноничный, правильный подход (REST):

  • Метод POST на коллекцию (типа /api/users) — это по сути крик «Создай мне что-то новое, а какой там id вылезет — твои проблемы, я потом узнаю».
  • Сервер сам генерирует id (чаще всего в БД), а в ответе любезно отдаёт 201 Created и ссылку на новорожденного в заголовке Location. Клиент доволен, архитектура не плачет.

Вот как это выглядит в коде, без всяких самодеятельностей:

app.post('/api/users', async (req, res) => {
  const userData = req.body; // { name: 'Alice', email: 'alice@example.com' }
  // id НЕ ожидается в userData
  const newUser = await db.users.create(userData); // Сервер генерирует id
  res.status(201).location(`/api/users/${newUser.id}`).json(newUser);
});

А когда эта дичь с id в POST может прокатить? Ну, бывает же, овердохуища случаев:

  1. Импорт данных: Тащишь тонну записей из старой системы, и там у каждой уже есть свой родной, любимый id, который надо сохранить. Делать нечего.
  2. Хитрая бизнес-логика: Если твой «айдишник» — это не скучный автоинкремент, а, скажем, артикул товара или номер договора, который придумывает сам клиент. Это уже часть данных, а не техническая метка.

Но слушай сюда, главное: если уж клиенту так приспичило самому указать, где и под каким ключом будет лежать ресурс — есть же метод PUT, ядрёна вошь! Он для этого и создан. PUT на конкретный URL — это чёткое заявление: «Создай или полностью перезапиши ресурс вот по этому адресу». И он идемпотентный, что всем разработчикам на руку.

В общем, в своих проектах я придерживаюсь простого правила: POST — это «создай, а id дашь потом», PUT/PATCH — «работай с тем, что я уже нашёл». Так API становится предсказуемым, и доверия к нему ебать не ноль, а вполне себе нормальный уровень. А то начнёшь позволять вольности — потом сам от себя охуеешь, разбирая, что где и как работает.