Люди говорят "не раскрывайте первичные ключи из базы данных в вашем API", потому что это большая утечка безопасности, поэтому я пытаюсь придумать способ:
Widget
с PK ID 293, поэтому я хочу получить эквивалент POST /myapi/widgets/293
, но без необходимости упоминать 293
.GET /myapi/widgets?color=blue
и все виджеты, которые вернутся в массиве JSON, не должны иметь своих DB PKЯ могу решить вторую проблему (чтение) с помощью DTO, и просто убедиться, что у меня есть WidgetDto
, который не включает поле Widget#id
вообще.
Но что касается ссылок на ресурсы без их ключей базы данных, каковы типичные решения здесь?
Единственное, что я могу придумать, это генерировать UUID для каждого ресурса (каждого Widget
) и хранить его в БД вместе с первичным ключом, например:
[widgets] table
===
[id] --> bigint primary key auto increment not null
[ref_id] --> varchar(36) not null (UUID)
...и затем часто менять UUID. Но это создает свои собственные головные боли, если что-то на стороне клиента кэшируется или в настоящее время использует ссылку на ресурс, а мы меняем его UUID на стороне сервера. Есть идеи? Спасибо!
Фундаментальная проблема с раскрытием простых суррогатных ключей, которые, как правило, являются первичными ключами базы данных, заключается в том, что это приводит к утечке вашей реализации за пределы вашей базы данных.
Если у вас есть API, который [кто-то узнает] поддерживает...
GET /myapi/widgets/293
...тогда ничто не мешает им попробовать...
GET /myapi/widgets/294
GET /myapi/widgets/295
GET /myapi/widgets/296
GET /myapi/widgets/297
. . .
... пока они не получат что-то обратно.
Другая проблема с этим подходом заключается в том, что эти значения [предположительно только для базы данных] могут сохраняться за пределами вашей базы данных. Допустим, ваше приложение знает, что оно работает с виджетом 21153, поэтому оно сохраняет это значение для собственного использования (неважно где). Затем ваша база данных подвергается реорганизации (по какой-либо причине), и все эти предположительно относящиеся только к базе данных внутренние значения изменяются. (Да, да, я знаю; первичные ключи никогда не должны меняться, но...)
В следующий раз, когда ваше приложение запустится, оно либо не сможет найти этот виджет, потому что у него теперь другой номер, либо, что еще хуже, оно вернет совершенно другой виджет (что в наши дни вполне может представлять собой нарушение данных).
Если вместо этого общение основано на естественном ключе, который идентифицирует ту же запись, в данном случае «очки Ladyman217», то этой проблемы можно полностью избежать.
Конечно, вам нужно «неформатировать» эти естественные ключи (в соответствующие значения первичного ключа) на пути «в», что означает, что больше индексов и тому подобное поддерживают это, и вам нужно «форматировать» в естественные ключи на обратном пути. "вне".
(То же самое можно сказать о датах и числах, но это уже другая история).
Ничего не приходит бесплатно.
По сути, связь базы данных с внешним миром должна осуществляться в терминах, значимых для внешнего мира. Утечка специфики базы данных только делает вещи более хрупкими в долгосрочной перспективе.