RESTful дизайн социальной сети - PullRequest
14 голосов
/ 16 февраля 2012

Я пытаюсь обернуть голову вокруг дизайна 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 (Convention over Configuration) будет предоставлять и 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, но всерьез ли кто-то считает, что для переключения языков в социальной сети он принадлежит?Должна ли вся эта информация каждый раз возвращаться вызывающей стороне, или я могу положиться на настройки?Будет ли это работать с кешем?

Ответы [ 2 ]

13 голосов
/ 17 февраля 2012

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

0 голосов
/ 16 февраля 2012

Если вы используете WCF Web Api (или даже не используете), возможно, стоит посмотреть на поддержку OData.Это действительно решает некоторые проблемы, которые делают поиск более доступным.

...