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

RESTful дизайн социальной сети

Я пытаюсь склонить голову вокруг дизайна RESTful, и я хотел бы понять это с точки зрения социальной сети. Я прочитал REST API Design Rulebook, просмотрел некоторые другие книги и прочитал много онлайн-ресурсов. Тем не менее, при применении правил к реальным проблемам я понимаю, что я не полностью понимаю все. Я хочу знать, есть ли у меня правильное понимание REST, указав некоторые проблемы:

Иерархия против плоского дизайна

Предположим, что я идентифицирую конкретного пользователя с

/users/42

Теперь фотографии, загруженные этим пользователем, попадут в

/users/42/photos

и если он/она помечает своих друзей на фотографии, те теги окажутся в

/users/42/photos/1337/tags

Но это не дает возможности найти все фотографии, где отмечен определенный пользователь. Должен ли я придумать для этого другую иерархию? Это кажется немного неудобным. Могу ли я полностью игнорировать иерархию и предоставлять фотографии в сочетании с такими запросами?

/photos?owner=42
/photos?tagged=42

Кэширование, когда контент отличается для разных пользователей

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

Предоставление HTML и JSON/XML из одного ресурса

В упомянутой книге указано правило, что API должен быть доступен в субдомене, начиная с api, в их примере http://api.soccer.restapi.org. Я планировал использовать один и тот же контроллер для доступа пользователей и доступа к машинам (например, мобильное приложение). Контроллер должен решить, какое представление предоставить (text/html, application/json или application/xml) через поле Accept в заголовке HTTP-запроса. Я полагаю, что по какой-то причине это было бы плохой идеей (поскольку пользователь ожидал увидеть субдомен www, а не api), но я не понимаю, почему. Может ли www и api указывать на один и тот же сервер, или я должен попытаться переместить вид HTML на другой виртуальный хост? Почему?

Я полагаю, что Ruby on Rails будет (Контекция по конфигурации) предоставлять как HTML, так и JSON от одного и того же контроллера, таким образом, разделяя мою идею о том, что HTML и JSON являются просто разными представлениями одних и тех же данных.

Другими словами, в моей книге говорится, что определенный ресурс должен иметь один и только один URI и что различные представления должны предоставляться на основе поля Accept. Перенаправление пользователя между разными субдоменами нарушит правило о предоставлении какого-либо представления с одного и того же ресурса, а дублирование информации (т.е. Указание двух поддоменов на один и тот же виртуальный хост) нарушает правило о том, чтобы не предоставлять несколько URI для одного и того же ресурса. Не предоставление субдомена api нарушает еще одно правило проектирования. Как я могу решить это без нарушения какого-либо правила?

Ограничение данных, отправленных обратно

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

/users

является незаконным запросом, а

/users?name=leet+hacker

будет действительным, но только вернется, например. 100 предметов.

Я также задаюсь вопросом, является ли законным возвращать подмножество столбцов базы данных и многое другое/все из них, только если они специально запрошены с использованием запроса.

Контроллеры, предоставляющие избыточные данные

Я считаю законным предоставлять контроллер, например

/users/me

но он должен предоставить ту же самую информацию, что и URI документа

/users/42

или должен ли он перенаправляться на него?

Расширенные права для некоторых пользователей

Каков RESTful способ предоставить дополнительные функции, например права администратора? Теперь я предполагаю, что администратор (фотографии, группы пользователей или всего сайта) сможет увидеть больше информации о конкретном объекте, чем другие пользователи. Должна ли эта информация храниться в точно таком же URI и автоматически отправляться администратору, но не кому-либо еще, должна ли она храниться в другом месте, если она запрашивается с использованием определенного запроса администратора или предоставляется каким-то другим способом?

Обновления локализации и настроек

Хотя большинство строк, видимых пользователю, должно быть предоставлено представлением, есть некоторые проектные решения, которые могут включать API. Наиболее очевидными являются имена. Социальные сети иногда позволяют пользователю вводить разные имена, которые должны отображаться в разных языковых контекстах. Имена на некоторых языках, например, на русском и арабском языках, не просто записываются автоматически. На других языках, таких как китайские, локальные и международные имена могут быть совершенно разными, без какого-либо сходства или связи. Каким был бы RESTful способ справиться с этим? У меня такое чувство, что ответом будет поле Accept-Language, но кто-нибудь всерьез рассматривает это для переключения языков в социальной сети, к которой они принадлежат? Должна ли вся эта информация возвращаться вызывающему абоненту каждый раз или я могу полагаться на настройки? Будет ли это работать с кешем?

4b9b3361

Ответ 1

Как отметил @Mark Dickinson, здесь есть много вопросов, которые действительно должны быть отдельными, но я сделаю все возможное.

Иерархия против плоского дизайна

В REST нет ничего, что указывало бы, что у вас не может быть несколько параллельных иерархий (хотя я понимаю, что делать это с Rails неудобно). Имея /users/42/photos/owner и /photos/owner/42, содержащие один и тот же набор, отлично. Аналогично /users/42/photos/tagged и /photos/tagged/42 могут содержать один и тот же набор. Однако вы не должны беспокоиться об URI в это время. Существует отличная статья API RESTful Hypermedia в трех простых шагах, в котором описывается, как разработать свой 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>

когда этот пользователь затем GETs /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 (Предполагая, что у вас есть разрешение на просмотр большого количества вредоносных хакеров в системе) создаст что-то вроде

<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>

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

Контроллеры, предоставляющие избыточные данные

Оба приемлемы. Однако, как указано выше (по причинам кэширования), я использовал бы /<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 для языка по умолчанию, но разрешите пользователю изменять язык в своих настройках.

Ответ 2

Если вы используете WCF Web Api (или даже если это не так), возможно, вам стоит посмотреть на поддержку OData. Он затрагивает некоторые проблемы, связанные с тем, чтобы сделать вещи более доступными для поиска.