Как отметил @Mark Dickinson, здесь много вопросов, которые действительно должны быть отдельными, но я сделаю все возможное.
Иерархия против плоского дизайна
Ничто в REST не говорит о том, что у вас не может быть нескольких параллельных иерархий (хотя я понимаю, что делать это с Rails неудобно). Имея /users/42/photos/owner
и /photos/owner/42
, содержащие один и тот же набор, это хорошо. Точно так же /users/42/photos/tagged
и /photos/tagged/42
могут содержать один и тот же набор. Тем не менее, вы не должны беспокоиться о URI в настоящее время. Есть отличная статья RESTful Hypermedia API в трех простых шагах , в которой описывается, как создать свой API. В этой статье URI определены как последний шаг.
Кроме того, используя HATEOAS , эти различные URI должны быть обнаружены клиентом во время выполнения по ссылкам и формам, предоставленным вашим приложением.
Кэширование при различном содержании для разных пользователей
Если вы собираетесь обслуживать другой контент с одного и того же URL-адреса, он не будет кэшироваться. Вы можете разделить ваш сайт на два типа контента, публичный и персонализированный. Публичный контент должен быть одинаковым для всех и может быть кэширован. Персонализированный контент отличается для каждого пользователя, что означает, что объем, который вы можете кэшировать, будет значительно сокращен (уменьшен до нуля, используя формат URL, который вы использовали в своих примерах).
Чтобы получить хотя бы небольшое количество кэширования на персонализированном контенте, разделите контент на части пользователя, чтобы у любого пользователя было несколько попаданий в кеш. Например, вместо /users/42
, к которому имеет доступ каждый, используйте /<UID>/users/42
где - ИД пользователя запрашивающего пользователя. например пользователь 234 получит доступ к странице профиля для пользователя 42, используя URI /234/users/42
. Для анонимных пользователей вы можете удалить часть /<UID
или использовать для них определенный идентификатор пользователя, например /public/users/42
.
Предоставление HTML и JSON / XML из одного и того же ресурса
Используйте заголовок Accept
. Вот для чего это.
Ограничение данных, отправляемых обратно
Вам не нужно делать /users
незаконный запрос. Лечить - это коллекция и возвращать список пользователей, разбитый на страницы, которые разрешено видеть запрашивающей стороне. Например, для анонимного запроса вы можете предоставить пустой список (или 204 Нет содержимого)
<users/>
и для конкретного вошедшего в систему пользователя, вы можете предоставить его друзьям.
<users>
<user id="42" href="/users/42" name="John Doe"/>
<user id="53" href="/users/53" name="Jane Doe"/>
...
<next href="/users?page=2"/>
</users>
когда этот пользователь ПОЛУЧИТ /users?page=2
, вы предоставите следующую страницу результатов
<users>
<user id="69" href="/users/69" name="John Smo"/>
<user id="84" href="/users/84" name="Jane Smo"/>
...
<next href="/users?page=3"/>
<prev href="/users"/>
</users>
На последней странице результатов отсутствует ссылка next
. Чтобы добавить возможность поиска, вы просто добавляете соответствующую форму как часть ответа.
<users>
<user id="69" href="/users/69" name="John Smo"/>
<user id="84" href="/users/84" name="Jane Smo"/>
...
<next href="/users?page=2"/>
<prev href="/users"/>
<search href="/users" method="get">
<name cardinality="required" type="regex"/>
</search>
</users>
Результаты поиска будут разбиты на страницы, как и список /users
. например, поиск leet hacker
(при условии, что у вас есть разрешение на просмотр большого количества хакеров leet в системе) выдает что-то вроде
<users>
<user id="234" href="/users/234" name="leet hacker"/>
<user id="999" href="/users/999" name="leet hacker"/>
...
<next href="/users?name=leet+hacker&page=2"/>
<search href="/users" method="get">
<name cardinality="required" type="regex"/>
</search>
</users>
однако вам, вероятно, потребуется предоставить более подробную информацию в пользовательском элементе, чтобы можно было отличить хакеров от leet.
Контроллеры, предоставляющие избыточные данные
Оба приемлемы. Однако, как указано выше (по причинам кэширования), я бы использовал /<UID>/users/42
, и в этом случае вы можете перенаправить /42/users/me
на /42/users/42
.
Это также помогает с аналитической точки зрения, поскольку вы можете отдельно отслеживать доступ пользователей к своей собственной странице, доступ пользователей к странице других пользователей, чтобы выяснить, какие пользователи популярны, а какие нарциссичны. Вы даже можете найти корреляцию между ними:)
Расширенные права для некоторых пользователей
Укажите админские ссылки и формы в соответствующем ответе. Например, доступ к деталям чужого изображения может обеспечить
<image id="266" href="/photos/266" caption="leet hacker with computer"
src="http://us.123rf.com/400wm/400/400/creatista/creatista0911/creatista091100003/5827629.jpg"/>
<tagged-users>
<user id="234" href="/users/234" name="leet hacker"/>
</tagged-users>
<owner id="234" href="/users/234" name="leet hacker"/>
</image>
но для владельца изображения это может предоставить
<image id="266" href="/photos/266" caption="leet hacker with computer"
src="http://us.123rf.com/400wm/400/400/creatista/creatista0911/creatista091100003/5827629.jpg"/>
<tagged-users>
<tagged-user id="234" href="/users/234" name="leet hacker">
<delete href="/photos/266/tagged/234" method="delete"/>
</tagged-user>
<add href="/photos/266" method="put">
<user cardinality="required" type="user-id"/>
</add>
</tagged-users>
<owner id="234" href="/users/234" name="leet hacker"/>
<delete href="/photos/266" method="delete"/>
<update href="/photos/266" method="put">
<caption cardinality="optional" type="string"/>
</update>
</image>
Обновления локализации и настроек
Используйте Accept-Language
для языка по умолчанию, но разрешите пользователю изменять язык в своих настройках.