Подтвердить что ты не робот

Дизайн RESTful: когда использовать суб-ресурсы?

При разработке иерархии ресурсов, когда нужно использовать под-ресурсы?

Раньше я полагал, что, когда ресурс не может существовать без другого, он должен быть представлен как его под-ресурс. Недавно я столкнулся с этим встречным примером:

  • Сотрудник уникально идентифицируется во всех компаниях.
  • Контроль доступа сотрудников и жизненный цикл зависят от компании.

Я смоделировал это как: /companies/{companyName}/employee/{employeeId}

Заметьте, мне не нужно искать компанию, чтобы найти сотрудника, так и я? Если я это сделаю, я заплачу цену за поиск информации, которая мне не нужна. Если я этого не сделаю, этот URL-адрес ошибочно возвращает HTTP 200:

/companies/{nonExistingName}/employee/{existingId}

  • Как я должен представить, что ресурс принадлежит другому?
  • Как я могу представить, что ресурс не может быть идентифицирован без другого?
  • Какие отношения представляют собой подресурсы, которые не предназначены для моделирования?
4b9b3361

Ответ 1

Через год я закончил следующий компромисс (для строк базы данных, которые содержат уникальный идентификатор):

  • Назначьте все ресурсы каноническим URI в корневом каталоге (например, /companies/{id} и /employees/{id}).
  • Если ресурс не может существовать без другого, он должен быть представлен как его под-ресурс; однако рассматривайте операцию как запрос поисковой системы. Значение, вместо того, чтобы немедленно выполнить операцию, просто верните HTTP 307 ("Temporary redirect"), указывая на канонический URI. Это заставит клиентов повторить операцию против канонического URI.
  • В вашем документе спецификации должны быть представлены только ресурсы root, соответствующие вашей концептуальной модели (не зависящей от деталей реализации). Детали реализации могут измениться (ваши строки больше не могут быть уникальными идентифицируемыми), но ваша концептуальная модель останется неизменной. В приведенном выше примере вы сообщаете клиентам о /companies, но не /employees.

Этот подход имеет следующие преимущества:

  • Это устраняет необходимость делать ненужные запросы базы данных.
  • Это уменьшает количество проверок работоспособности на один запрос. В лучшем случае я должен проверить, принадлежит ли сотрудник компании, но мне больше не нужно выполнять две проверки проверки для /companies/{companyId}/employees/{employeeId}/computers/{computerId}.
  • Это влияет на масштабируемость базы данных. С одной стороны, вы уменьшаете блокировку, блокируя меньше таблиц за более короткий период времени. Но, с другой стороны, вы увеличиваете вероятность взаимоблокировок, потому что каждый корневой ресурс должен использовать другой порядок блокировки. Я не знаю, является ли это чистой прибылью или потерей, но я уверен, что блокировки базы данных не могут быть предотвращены, и результирующие правила блокировки проще понять и воплощать в жизнь. Если вы сомневаетесь, выберите простоту.
  • Наша концептуальная модель остается нетронутой. Убедившись, что документ спецификации только раскрывает нашу концептуальную модель, мы вправе отказаться от URI, содержащих детали реализации в будущем, без нарушения существующих клиентов. Помните, ничто не мешает вам раскрывать детали реализации в промежуточных URI, пока ваша спецификация объявляет их структуру как undefined.

Ответ 2

Это проблематично, потому что уже не очевидно, что пользователь принадлежит для конкретной компании.

Иногда это может указывать на проблему с вашей моделью домена. Почему пользователь принадлежит компании? Если я смену компании, я весь новый человек? Что делать, если я работаю для двух компаний? Я два разных человека?

Если да, то почему бы не взять какой-то уникальный для компании идентификатор для доступа к пользователю?

например. Имя пользователя:

company/foo/user/bar

(где bar - мое имя пользователя, которое уникально в пределах этого пространства имен конкретной компании)

Если ответ отрицательный, то почему я сам не являюсь пользователем (человеком), а коллекция company/users просто указывает на меня: <link rel="user" uri="/user/1" /> (обратите внимание: сотрудник кажется более подходящим)

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

Я имею в виду, что users на самом деле является под-ресурсом ресурса компании, потому что использование заключается в определении отношений между компанией и ее сотрудниками - еще один способ сказать, что это: вы должны определить компании, прежде чем вы сможете начать нанимать сотрудников. Аналогично, пользователь (человек) должен быть определен (рожден), прежде чем вы сможете его нанять.

Ответ 3

Ваше правило, чтобы решить, должен ли ресурс быть смоделирован как вспомогательный ресурс, действителен. Ваша проблема не возникает из-за неправильной концептуальной модели, но вы можете пропустить вашу модель базы данных в свою модель REST.

Из концептуального представления employee, если он может существовать только в рамках отношения company, моделируется как composition. Таким образом, employee можно было идентифицировать только с помощью company. Теперь вступают в действие базы данных, и все строки employee получают уникальный идентификатор.

Мой совет не позволяет модели базы данных течь в вашей концептуальной модели, потому что вы подвергаете инфраструктуру своим API. Например, что происходит, когда вы решите переключиться на документально ориентированную базу данных, такую ​​как MongoDB, где вы могли бы моделировать своих сотрудников как часть документа компании и больше не иметь этот уникальный уникальный идентификатор? Вы хотите изменить свой API?

Чтобы ответить на дополнительные вопросы

Как я должен представлять факт, что ресурс принадлежит другому?

Состав через вспомогательные ресурсы, другие ассоциации через URL-ссылки.

Как я могу представить, что ресурс не может быть идентифицирован без другого?

Используйте оба значения id в URL-адресе вашего ресурса и не позволяйте вашей базе данных течь в ваш API, проверяя, существует ли "комбинация".

Какими отношениями являются подресурсы, которые не предназначены для моделирования?

Субресурсы хорошо подходят для композиций, но в более общем плане говорят о том, что ресурс не может существовать без родительского ресурса и всегда принадлежит одному родительскому ресурсу. Ваше правило when a resource could not exist without another, it should be represented as its sub-resource является хорошим ориентиром для этого решения.

Ответ 4

если подресурс уникально идентифицируется без его собственного объекта, он не является подресурсом и должен иметь собственное пространство имен (то есть /users/ {user}, а не /companies/ {*}/users/{user}). Самое главное: никогда никогда не использует первичный ключ базы данных сущности в качестве идентификатора ресурса. что наиболее распространенная ошибка, когда детали реализации протекают во внешний мир. у вас всегда должен быть натуральный бизнес-ключ (например, имя пользователя или номер компании, а не идентификатор пользователя или идентификатор компании). уникальность такого ключа может быть принудительно применена с помощью уникального ограничения, если вы хотите, но первичный ключ объекта никогда не должен покидать уровень персистентности вашего приложения или, по крайней мере, он никогда не должен быть аргументом какой-либо службы метод. Если вы придерживаетесь этого правила, вам не должно быть никаких проблем с различиями между композициями (/companies/{company}/users/{user}) и ассоциациями (/users/{user}), потому что если ваш субресурс не имеет естественный бизнес-ключ, который идентифицирует его в глобальном контексте, вы можете быть уверены, что он действительно является зависимым субресурсом (или вы должны сначала создать бизнес-ключ, чтобы сделать его глобально идентифицируемым).

Ответ 5

Это один из способов решения этой проблемы:

/companies/{companyName}/employee/{employeeId} → возвращает данные о сотруднике, также должны включать данные лица

/person/{peopleId} → возвращает данные о человеке

Говорить о сотруднике нет смысла, не говоря о компании, но говорить о человеке имеет смысл даже без компании и даже если он нанят несколькими компаниями. Существование человека не зависит от того, наняли ли он какие-либо компании, но существование занятости зависит от компании.

Ответ 6

Кажется, что проблема связана с отсутствием конкретной компании, но сотрудник технически принадлежит какой-либо компании или организации, иначе их можно было бы назвать бомжками или политиками. Быть сотрудником подразумевает отношения компании/организации где-то, но не конкретные. Также сотрудники могут работать более чем в одной компании/организации. Когда требуется конкретный контекст компании, ваши оригинальные работы /companies/{companyName}/users/{id}

Допустим, вы хотите узнать EmployerContribution для своей ira/rsp/pension, которую вы будете использовать: /companies/enron/users/fred/EmployerContribution Вы получаете определенную сумму, внесенную enron (или $0).

Что делать, если вы хотите, чтобы EmployerContribution от любых или всех компаний fred работал (ed) для?
Вам не нужна конкретная компания, чтобы это имело смысл. /companies/any/employee/fred/EmployerContribution

Если "любое" является, очевидно, абстракцией или заполнителем, когда компания-сотрудник не имеет значения, но является работником. Вам нужно перехватить обработчик "компании", чтобы предотвратить поиск db (хотя не уверен, почему компания не будет кэшироваться? Сколько их может быть?)

Вы можете даже изменить абстракцию, чтобы представить что-то вроде всех компаний, для которых Фред работал на протяжении последних 10 лет. /companies/last10years/employee/fred/EmployerContribution