2015-02-04 2 views
2

Впервые я думаю об этом ...Должен ли возвращаться натуральный или суррогатный ключ в API?

До сих пор я всегда использовал естественный ключ в своем API. Например, REST API, позволяющий обрабатывать объекты, URL-адрес будет выглядеть как /entities/{id}, где id является естественным ключом, известным пользователю (идентификатор передается запросу POST, который создает объект). После создания сущности пользователь может использовать несколько команд (GET, DELETE, PUT ...) для управления объектом. Сущность также имеет суррогатный ключ, созданный базой данных.

Теперь подумайте о следующей последовательности:

  1. Пользователь создает объект с идентификатором 1. (POST /entities с телом, содержащим ид 1)
  2. Другой пользователь удаляет объект (DELETE /entities/1)
  3. То же самое другой пользователь снова создает объект (POST /entities с телом, содержащим идентификатор 1)
  4. Первый пользователь принимает решение об изменении лица (PUT /entities/1 с кузовом)

Прежде чем выполнить шаг 4, в базе данных все еще есть объект с идентификатором 1, но это не тот же объект, созданный во время шага 1. Проблема заключается в том, что на этапе 4 определяется, что сущность модифицируется на основе естественного ключа что одинаково для удаленной и новой сущности (в то время как суррогатный ключ отличается). Поэтому шаг 4 будет успешным, и пользователь никогда не узнает, что он работает над новым объектом.

Я вообще также использую оптимистичную блокировку в своих приложениях, но я не думаю, что это помогает здесь. После шага 1 поле версии сущности равно 0. После шага 3 поле версии нового объекта также равно 0. Поэтому проверка версии не поможет. Правильно ли использовать поле метки времени для оптимистической блокировки?

Является ли "хорошим" решением для возврата суррогатного ключа пользователю? Таким образом, пользователь всегда предоставляет суррогатный ключ серверу, который может использовать его для обеспечения того, чтобы он работал на одном и том же объекте, а не на новом?

Какой подход вы рекомендуете?

Спасибо, Микаэль

+0

Для заинтересованных пользователей посмотрите на чат с Gaz_Edge (ссылку на чат можно найти в последнем комментарии принятого ответа). –

ответ

2

Это зависит от того, как вы хотите, чтобы пользователи пользователя вашего API.

REST API должны пытаться быть открываемыми. Поэтому, если есть польза в раскрытии естественных ключей в вашем API, потому что это позволит пользователям напрямую изменять URI и перейти в новое состояние, тогда сделайте это.

Хорошим примером являются категории или теги. У нас могут быть следующие URI;

GET /some-resource?tag=1 // returns all resources tagged with 'blue' 
GET /some-resource?tag=2 // returns all resources tagged with 'red' 

или

GET /some-resource?tag=blue // returns all resources tagged with 'blue' 
GET /some-resource?tag=red // returns all resources tagged with 'red' 

Существует явно больше значения для пользователя во второй группе, так как они могут видеть, что тег является реальным словом.Затем это позволяет им набирать любое слово там для того чтобы увидеть вернулся, в то время как первая группа не позволяет этого: он ограничивает понятности

Другой пример был бы приказ

GET /orders/1 // returns order 1 

или

GET /orders/some-verbose-name-that-adds-no-meaning // returns order 1 

В этом случае мало значения при добавлении некоторого подробного имени в заказ, чтобы он мог быть доступен для обнаружения. Пользователь, скорее всего, хотят, чтобы просмотреть все заказы первого (или подмножество) и фильтр по дате или цене и т.д., а затем выбрать порядок просмотра

GET /orders?orderBy={date}&order=asc 

Дополнительная

После нашего обсуждения более чат, ваша проблема, похоже, связана с управлением версиями и управлением блокировкой ресурсов.

Если вы разрешаете изменениям ресурсов несколькими пользователями, вам необходимо отправить номер версии с каждым запросом и ответом. Номер версии увеличивается при каждом изменении. Если запрос отправляет более старый номер версии при попытке изменить ресурс, выведите ошибку.

В случае, когда вы разрешаете повторять использование одинаковых URI, существует вероятность конфликта, так как номер версии всегда начинается с 0. В этом случае вам также необходимо будет отправить GUID (суррогатный ключ) и номер версии. Или не используйте естественные URI (см. Исходный ответ выше, чтобы решить, когда делать это или нет).

Существует еще один вариант, запрещающий повторное использование URI. Это действительно зависит от варианта использования и требований вашего бизнеса. Возможно, было бы хорошо использовать URI, поскольку концептуально это означает одно и то же. Например, если на вашем компьютере была папка. Удаление папки и ее повторное создание - это то же самое, что и удаление папки. Концептуально папка - это то же самое «вещь», но с разными свойствами.

Учетная запись пользователя, вероятно, является областью, где повторное использование URI не является хорошей идеей. Если вы удалите учетную запись/учетные записи/u1, этот URI должен быть помечен как удаленный, и ни один другой пользователь не сможет создать учетную запись с именем пользователя u1. Понятно, что новый пользователь, использующий тот же URI, не совпадает с тем, который использовался предыдущим пользователем.

+0

Спасибо за ваш ответ. Как насчет вопроса, который я описал в вопросе? –

+0

Я в замешательстве. Я попытался ответить на ваш вопрос об открытии суррогатных или естественных ключей ... я что-то пропустил? –

+0

Да, но мой вопрос был больше обусловлен тем, что я представляю. Когда пользователь использует естественные ключи с API, он работает с логическим объектом (например, объект с естественным идентификатором 1). Когда используется суррогатный ключ, он работает с физическим объектом (например, объект с идентификатором 125648555845). Проблема в том, что когда пользователь получает объект на основе натурального ключа, он получает физический объект.Когда он пытается удалить его, он может удалить другой физический объект с тем же естественным ключом. –

0

Вы упомянули о возможности использования временной метки в качестве вашей оптимистической блокировки.

В зависимости от того, насколько строго вы следуете принципу RESTful, Entity, возвращаемая POST, будет содержать ссылку «отредактировать себя»; это URI, с которым можно выполнить DELETE или UPDATE.

Принимая свои действия, описанные выше в качестве примера:

Шаг 1

Пользователь А делает ПОСТ Entity 1. Возвращаемый объект Объект будет содержать «Я» ссылку, указывающую, где должны происходить обновления, как:

/entities/1/timestamp/312547124138 

Шаг 2

Пользователь B получает существующий объект 1 с указанной выше ссылкой «self» и выполняет DELETE для этого URI с меткой времени.

Шаг 3

пользователь B делает пост нового Entity 1, который возвращает объект с другим "Я" ссылку, например:

/entities/1/timestamp/312547999999 

Шаг 4

Пользователь A, с оригинальной Сущностью, полученной ими на шаге 1, пытается выполнить PUT на ссылку «self» на своем объекте, которая была:

/entities/1/timestamp/312547124138 

... ваше обслуживание признает, что хотя Сущность 1 существует; Пользователь A пытается выполнить PUT против версии, которая с тех пор устарела.

Затем служба может выполнить соответствующее действие. В зависимости от того, насколько изощрен ваш алгоритм, вы можете либо объединить изменения, либо отклонить PUT.

Я не могу вспомнить соответствующий код статуса HTTP, который вы должны вернуть, после PUT для устаревшей версии ... Это не то, что я реализовал в рамках Rest, в котором я работаю, хотя я планировал чтобы включить его в будущем. Возможно, вы вернете 410 («Gone»).

Шаг 5

Я знаю, что вы не шаг 5, но ..! Пользователь А, при нахождении их PUT не удалось, может повторно получить Entity 1. Это может быть GET их (черствый) версии, т.е. GET для:

/entities/1/timestamp/312547124138 

... и ваша служба будет возвращать перенаправить GET либо из родового URI для этого объекта, например:

/entities/1 

... или к конкретной последней версии, а именно:

/entities/1/timestamp/312547999999 

затем они могут сделать изменения предназначены в шаге 4 , с учетом любого приложения l логика слияния.

Надеюсь, что помогает.

0

Ваша проблема может быть решена либо с помощью ETags для управления версиями (запись может быть изменена только при наличии текущего ETag), либо путем мягких удалений (поэтому удаленная запись все еще существует, но с отключенным bool, который сбрасывается PUT) ,

Похоже, вы также можете воспользоваться конечной точкой партии и использовать транзакции.

 Смежные вопросы

  • Нет связанных вопросов^_^