Представьте, что у вас есть 2 объекта: игрок и команда , где игроки могут быть в нескольких командах. В моей модели данных у меня есть таблица для каждой сущности и таблица соединений для поддержания отношений. Hibernate прекрасно справляется с этим, но как я могу представить эти отношения в RESTful API?
Я могу придумать пару способов. Во-первых, у меня может быть каждый объект, содержащий список другого, поэтому у объекта Player будет список Команд, к которым он принадлежит, и у каждого объекта Team будет список игроков, которые ему принадлежат. Таким образом, чтобы добавить игрока в команду, вы просто поместите представление игрока в конечную точку, что-то вроде POST /player
или POST /team
с соответствующим объектом в качестве полезной нагрузки запроса. Это кажется мне самым «ОТЛИЧНЫМ», но кажется немного странным.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png',
players: [
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
Другой способ, которым я могу придумать, состоит в том, чтобы представить отношения как ресурс сам по себе. Таким образом, чтобы увидеть список всех игроков в данной команде, вы можете сделать GET /playerteam/team/{id}
или что-то в этом роде и получить список объектов PlayerTeam. Чтобы добавить игрока в команду, POST /playerteam
с соответствующим образом созданным объектом PlayerTeam в качестве полезной нагрузки.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png'
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
/api/player/team/0/:
[
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
Какова лучшая практика для этого?
источник
Я бы сопоставил такие отношения с подресурсами, тогда общий дизайн / обход был бы:
В терминах Restful это очень помогает не думать о SQL и соединениях, а больше о коллекциях, вложенных коллекциях и обходе.
Некоторые примеры:
Как вы видите, я не использую POST для размещения игроков в командах, а PUT, который лучше обрабатывает ваши отношения игроков и команд.
источник
status
как параметр в запросе PUT? Есть ли обратная сторона этого подхода?Существующие ответы не объясняют роли последовательности и идемпотентности, которые мотивируют их рекомендации
UUIDs
/ случайными числами для идентификаторов иPUT
вместоPOST
.Если мы рассмотрим случай, когда у нас есть простой сценарий, такой как « Добавить нового игрока в команду », мы столкнемся с проблемами согласованности.
Поскольку игрок не существует, нам нужно:
Однако, если клиентская операция завершится неудачно после
POST
to/players
, мы создали игрока, который не принадлежит команде:Теперь у нас есть дублированный игрок-сирота
/players/5
.Чтобы исправить это, мы могли бы написать собственный код восстановления, который проверяет осиротевших игроков, которые соответствуют некоторому естественному ключу (например
Name
). Это пользовательский код, который необходимо протестировать, стоит больше денег и времени и т. Д.Чтобы избежать необходимости настраиваемого кода восстановления, мы можем реализовать
PUT
вместоPOST
.Из RFC :
Чтобы операция была идемпотентной, она должна исключать внешние данные, такие как сгенерированные сервером последовательности идентификаторов. Вот почему люди рекомендуют оба
PUT
иUUID
с дляId
S вместе.Это позволяет нам повторно запустить
/players
PUT
и/memberships
PUT
без последствий:Все хорошо, и нам не нужно было ничего делать, кроме как повторить попытку частичных сбоев.
Это скорее дополнение к существующим ответам, но я надеюсь, что это помещает их в контекст более широкой картины того, насколько гибкими и надежными могут быть ReST.
источник
23lkrjrqwlej
?Моя предпочтительным решением является создание трех ресурсов:
Players
,Teams
иTeamsPlayers
.Итак, чтобы получить всех игроков команды, просто зайдите на
Teams
ресурс и получите всех ее игроков, позвонивGET /Teams/{teamId}/Players
.С другой стороны, чтобы получить все команды, в которых играл игрок, получите
Teams
ресурс внутриPlayers
. ВызовGET /Players/{playerId}/Teams
.И, чтобы получить вызов отношения многих ко многим
GET /Players/{playerId}/TeamsPlayers
илиGET /Teams/{teamId}/TeamsPlayers
.Обратите внимание, что в этом решении при вызове
GET /Players/{playerId}/Teams
вы получаете массивTeams
ресурсов, который в точности совпадает с ресурсом, который вы получаете при вызовеGET /Teams/{teamId}
. Обратное следует тому же принципу, вы получаете массивPlayers
ресурсов при вызовеGET /Teams/{teamId}/Players
.В любом из вызовов информация об отношениях не возвращается. Например, нет
contractStartDate
возвращается, потому что возвращаемый ресурс не имеет информации об отношении, только о своем собственном ресурсе.Чтобы разобраться с отношениями nn, позвоните либо
GET /Players/{playerId}/TeamsPlayers
илиGET /Teams/{teamId}/TeamsPlayers
. Эти вызовы возвращают именно ресурс,TeamsPlayers
.Этот
TeamsPlayers
ресурс имеетid
,playerId
,teamId
атрибуты, а также некоторые другие , чтобы описать отношения. Кроме того, у него есть методы, необходимые для борьбы с ними. GET, POST, PUT, DELETE и т. Д., Которые будут возвращать, включать, обновлять, удалять ресурс отношений.В
TeamsPlayers
инвентаре ресурсов некоторых запросы, какGET /TeamsPlayers?player={playerId}
вернуть всеTeamsPlayers
отношения игрок идентифицируется{playerId}
имеет. Следуя той же идее, используйтеGET /TeamsPlayers?team={teamId}
для возврата все,TeamsPlayers
что сыграло в{teamId}
команде. При любомGET
вызове ресурсTeamsPlayers
возвращается. Все данные, связанные с отношениями, возвращаются.При вызове
GET /Players/{playerId}/Teams
(илиGET /Teams/{teamId}/Players
) ресурсPlayers
(илиTeams
) вызываетTeamsPlayers
возврат связанных команд (или игроков) с использованием фильтра запросов.GET /Players/{playerId}/Teams
работает так:Вы можете использовать тот же алгоритм, чтобы получить всех игроков из команды, при вызове
GET /Teams/{teamId}/Players
, но обмениваетесь командами и игроками.Мои ресурсы будут выглядеть так:
Это решение опирается только на ресурсы REST. Хотя для получения данных от игроков, команд или их отношений могут потребоваться дополнительные вызовы, все методы HTTP легко реализуются. POST, PUT, DELETE просты и понятны.
Всякий раз, когда связь создается, обновляется или удаляется,
Players
иTeams
ресурсы, и ресурсы обновляются автоматически.источник
Я знаю, что есть ответ, помеченный как принятый для этого вопроса, однако, вот как мы могли бы решить ранее поставленные вопросы:
Скажем для PUT
Например, все приведенные ниже результаты приведут к одному и тому же эффекту без необходимости синхронизации, поскольку они выполняются на одном ресурсе:
Теперь, если мы хотим обновить несколько членств для одной команды, мы можем сделать следующее (с соответствующими проверками):
источник
Я предпочитаю 2
источник