> ## Documentation Index
> Fetch the complete documentation index at: https://docs.1unic.com/odatav4/llms.txt
> Use this file to discover all available pages before exploring further.

# Надёжная запись

> ETag, повторяемые запросы, ключ нового объекта и проверка ссылок

## ETag и оптимистическая блокировка

Версия объекта — `W/"<DataVersion>"`.

* Сущность по ключу и ответы записи несут заголовок `ETag`.
* Каждая сущность в выдаче несёт `@odata.etag`, если выбран `DataVersion`.

| Заголовок | Поведение |
| - | - |
| `If-Match: W/"…"` | Запись выполняется, только если версия совпадает. Иначе `412` |
| `If-Match: *` | Любой существующий объект |
| `If-None-Match: *` | Только создание: если объект существует, `412` |

У записей регистров и констант версии нет, для них подходит только `If-Match: *`.

Флажок **«Требовать If-Match»** на вкладке «Запись» (по умолчанию выключен) делает заголовки обязательными. `PATCH`, `PUT`, `DELETE`, `Post` и `Unpost` без `If-Match` получают `428`, а `POST` без `If-None-Match: *` — тоже `428`.

## Повторяемые запросы

Сеть может оборвать ответ после того, как объект уже записан. Чтобы повтор не создал дубль, передайте один из заголовков:

* `Repeatability-Request-ID` (OData 4.01). Учитываются также `Repeatability-Client-ID` и `Repeatability-First-Sent`;
* `Idempotency-Key`.

```http theme={null}
POST /base/hs/odata/v4/Document_РеализацияТоваровУслуг
Content-Type: application/json
Idempotency-Key: 6f1c2a7e-4b0d-4d61-9a55-1b9f0d6c3e21

{ … }
```

Как это работает:

* Запрос выполняется в одной транзакции с сохранением ответа. Ключ — субъект и хеш заголовка с его значением.
* Повтор с тем же ключом от того же субъекта ждёт окончания первого запроса и получает сохранённый ответ (статус, заголовки, тело). Повторно запрос не выполняется.
* Тот же ключ с другим методом, адресом или телом — `422`.
* `Repeatability-First-Sent` старше срока хранения — `400`.
* С `Repeatability-Request-ID` ответ несёт `Repeatability-Result: accepted`, у отказов — `rejected`.
* Ответы с ошибкой не хранятся: запись откатилась, и повтор выполняется заново.
* Срок хранения задаёт поле «Срок хранения повторов, часов» на вкладке «Запись» (по умолчанию 24). Старые записи удаляет регламентное задание «Очистка OData4».
* В `$batch` заголовок действует для отдельных операций (он ставится в операции), но не для пакета целиком.

Ответ записи, в том числе с `$expand`, собирается до фиксации транзакции. Если сборка ответа сорвалась, откатывается и запись, поэтому `500` после уже записанного объекта из-за ответа не бывает.

## Ключ нового объекта

`Ref_Key` в теле `POST` задаёт ссылку нового объекта. Занятость ключа проверяется в транзакции записи среди всех объектов, включая скрытые профилем и RLS. Параллельные `POST` с одним ключом дают один `201` и один `409`, дубля нет.

Ответ `409` на ключ скрытого объекта раскрыл бы, что объект существует. Поэтому субъекту, у которого для набора есть отборы строк профиля, `Ref_Key` по умолчанию запрещён: ответ `400` «Свойство Ref\_Key: ключ нового объекта задаёт сервис…». Настройка «Ключ при создании» = «Разрешён» снимает запрет. Тогда `409` одинаков для видимого и скрытого объекта, а существование скрытого объекта по известному GUID можно узнать.

## Проверка ссылок тела

Каждая непустая ссылка в теле записи должна вести на существующий объект, который субъект видит при чтении. Это касается ссылок на справочник, документ, план, узел обмена, бизнес-процесс или задачу в реквизите, `…@odata.bind`, составном поле, строке табличной части и строке набора движений. Видимость определяют набор модели профиля, его отборы строк и RLS.

Если ссылка не проходит проверку, ответ — `400` «Свойство X: объект не найден или недоступен». У строки табличной части свойство указывается как `ТЧ[N]/X`, у набора движений — `RecordSet[N]/X`. Текст одинаков для «нет» и «не видно».

* Значение, которое уже было у объекта в этом поле, не проверяется. Объект со ссылкой на скрытое можно менять, не трогая её.
* Объекты видов вне состава публикации проверяются только на существование и RLS.

Режим выбирается в настройке «Проверка ссылок записи»:

| Режим | Проверка |
| - | - |
| Видимость профилю (по умолчанию) | Существование, отборы профиля и RLS |
| Существование | Без профиля: только права 1С и RLS |
| Не проверять | Как у `standard.odata` |

## Как безопасно повторять запрос

Если ответ потерян или пришёл `500`, объект мог быть уже записан. Повторяйте так:

<AccordionGroup>
  <Accordion title="Любой запрос записи">
    Передавайте `Repeatability-Request-ID` или `Idempotency-Key`. Повтор получит сохранённый ответ без повторного выполнения.
  </Accordion>

  <Accordion title="Создание без заголовка повторяемости">
    Задайте свой `Ref_Key` и `If-None-Match: *`. Повтор получит `412` или `409`, объект останется один. Субъекту с отборами строк профиля `Ref_Key` по умолчанию закрыт (см. выше).
  </Accordion>

  <Accordion title="PATCH и PUT">
    Повторяйте с `If-Match`. Если запись прошла, версия уже другая, и повтор получит `412`.
  </Accordion>

  <Accordion title="DELETE, Post, Unpost">
    Прочитайте объект и проверьте результат: пометку удаления или признак `Posted`.
  </Accordion>
</AccordionGroup>

<Note>
  Изредка при включённом журнале запросов платформа отвечает `500` «Тип не определен '…'» на первый запрос после простоя сеанса. Запрос записи к этому моменту уже зафиксирован, поэтому повторяйте его одним из способов выше. Подробнее — на странице [Известные ограничения](/odatav4/reference/limitations).
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.