Должен ли веб-сайт быть веб-ресурсом?

Каждое веб-приложение - каждый веб-сайт - это услуга. (...) Функции, облегчающие использование веб-сайта для веб-пользователя, также облегчают использование API веб-службы для программиста.

Ричардсон и Руби, "RESTFul Web Services"

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

Это не так для многих популярных "REST API" в дикой природе. API Twitter, например, находится по адресу http://api.twitter.com/1/, где "1" в URI является версией самого API. Socialcast также предоставляет REST API по адресу https://demo.socialcast.com/api/, именем третьего уровня является имя сети, к которой он обращается.

Это кажется мне неправильным. Если у меня есть блог на http://www.example.com/blog, мне не нужно предоставлять API в другом месте, обслуживая JSON только для роботов. Вместо того чтобы иметь http://www.example.com/blog/posts/ и http://api.example.com/blog/posts, два разных URI, я должен иметь только первое и несколько доступных представлений, среди которых application/json для JSON API я хочу предоставить своим пользователям.

Пример 1: браузер запрашивает сообщения в моем блоге;

Запрос:

curl -i \
 -H "Accept: text/html" \
 -X GET \
 http://www.example.org/blog/posts/

Отклик:

 200 OK
 Content-Type: text/html; charset=utf-8

 <html><body><h1>Posts</h1><ol><li><h2>My first post ...

Пример 2: тот же URI, но на этот раз робот делает запрос;

Запрос:

curl -i \
 -H "Accept: application/json" \
 -X GET \
 http://www.example.org/blog/posts/

Отклик:

 200 OK
 Content-Type: text/html; charset=utf-8

 {
    "posts": [
        {
            "id": 1,
            "title": "My first post" ...

Номера версий для API должны быть закодированы в поле "Принять" заголовков запросов, и, прежде всего, избегать строгой типизации URI, как это делает Твиттер ("statuses/show.json? Id=210462857140252672" или "statuses/show/210462857140252672.json"). ").

Я мог бы потерять некоторую гибкость, перейдя на унифицированный подход (но разве Cool URI никогда не изменятся?), Но я думаю, что присоединение к REST (или, по крайней мере, моя интерпретация этого) принесло бы больше пользы.

Какой подход является более правильным: разделить API и веб-сайт или объединить их?

4 ответа

Решение

Здесь нет правильного или неправильного. Слишком близкое следование REST и RFC может оказаться затруднительным, если разработка вашего API определяется конкретными требованиями клиента.

В действительности, люди-люди имеют разные модели поведения по сравнению с клиентами API, и поэтому требуют другого подхода. Наиболее яркое различие заключается в том, что многие API-интерфейсы очень интенсивно используют данные, предназначены для пакетных операций и сброса данных, в то время как приложения для пользователей более "реагируют" и часто выполняют пошаговые действия, запрос за запросом. Как следствие, во многих проектах дизайн URL-адресов API оптимизирован, чтобы избежать напрасной траты ресурсов клиента и сервера на многочисленные обходы сети и повторные вызовы хранилища.

Внутренние реализации API часто отличаются от базовых приложений и оптимизированы для операций, которые предоставляют API. Например, реализация API может использовать отдельную стратегию кэширования. Теперь, если вы разделите код, вы можете создать кластер хостов, которые будут обрабатывать только вызовы API. Именно здесь размещение API в другом домене становится выгодным для управления нагрузкой: отдельный домен обеспечивает более простую балансировку нагрузки на сайтах с высокой нагрузкой. Для сравнения, если вы используете префикс / api URL для того же доменного имени (но с отдельными кластерами), то вам нужен умный (с поддержкой L7) балансировщик нагрузки, чтобы разделить поток запросов между API и интерфейсными веб-кластерами, но такие балансировщики нагрузки дороже.

Поэтому могут быть очень веские технические причины, по которым подобные Твиттеры отделяют API, но ссылки на другие реализации могут не относиться к ВАШЕМУ проекту. Если вы находитесь на ранних стадиях разработки, вы можете начать с унифицированной схемы URL в том же домене, но в конечном итоге вы можете обнаружить, что есть хорошие реальные сценарии использования, которые заставляют вас изменить подход, а затем... рефакторинг.

PS здесь есть длинная дискуссия о версиях - лучшие практики для управления версиями API?

PSS Я нахожу строго типизированные URL-адреса полезными в быстрой отладке. Вы можете просто вставить URL в браузер с помощью.json и быстро получить результат, не переключаясь на командную строку. Но согласен с вами, что заголовок "принять" является предпочтительным методом

PSSS SEO для API? Я вижу, как хороший дизайн URL может быть полезен, но для поисковой системы, вероятно, не имеет значения, если ваш сервис предоставляет несколько выходных форматов для одного пути / доменного имени. В конце концов, поисковые системы созданы для пользователей, а пользователи не используют XML и JSON.

Web и RESTful API могут вести себя по-разному.

Теоретически, как бы запрос как http://mysite.com/blog/1 различает, нужно ли возвращать HTML-страницу или только данные (JSON, XML...)? Я буду голосовать за использование Accept Заголовок http:

Accept: text/html <-- Web browsers
Accept: application/json <-- Applications/Relying parties consuming data or performing actions

Почему Twitter, Facebook или другие сайты не смешивают как веб-браузеры, так и проверяющие стороны? Честно говоря, я бы сказал, что это произвольное решение.

Возможно, я могу привести одну возможную причину: URL -адреса веб-браузера / робота поисковой системы должны быть дружественными, потому что они лучше работают в SEO. По этой причине, возможно, SEO-готовые URL не очень семантические с точки зрения REST, но они предназначены для поисковой системы или даже для пользователей!

Напоследок: что лучше (это мое мнение)?

  • Вам нужен SEO, затем используйте отдельные URL.
  • Вам не нужно SEO, а затем объедините URL-адреса в одном домене и формате.

Я не согласен с другим ответом, что это решение должно иметь какое-либо отношение к SEO или к тому, насколько "дружелюбен" URL-адрес (роботы тоже [написаны] людьми!). Но моя интуиция подсказывает мне, что лучшие результаты SEO будут получены при объединении URI, поскольку это также объединяет PageRank в (маловероятном) событии, с которым ваши URI API будут связаны с миром дикой сети.

То, на чем должно основываться это решение - это то, на что способны ваш сервер и клиенты. Если они могут установить заголовки запросов Accept, а ваш сервер достаточно умен, чтобы осуществлять прозрачное согласование контента, то непременно объедините URI. Это то, что я делаю (хотя мой единственный JSON-клиент - это я сам, выдающий AJAX-запросы, обслуживаемые другими HTML-частями моего веб-приложения, где я контролирую заголовок Accept).

Если клиент не может установить заголовки запроса, например, веб-пользователь, желающий получить ответ json, он получит значение по умолчанию (предположительно text / html). По этой причине вы можете разрешить возникновение необъявленных ответов под уникальными URI (/foo.txt, /foo.rtf). Обычно это делается путем добавления формата к URI, разделенному точкой, как если бы это было расширение имени файла (но обычно это не так, mod_rewrite выполняет жонглирование), чтобы старые клиенты на платформах, которым нужны расширения имени файла, могли сохранить файл. с осмысленным.

Большинство страниц на моем сайте работают примерно так:

  1. Определить запрос SQL по URL запроса. (например /cars?colour=black => SELECT * FROM cars WHERE colour='black')
  2. Выдать SQL-запрос.
  3. Определите приемлемый тип ответа из списка, поддерживаемого этим файлом. Обычно это HTML и HAL (т.е. JSON), хотя иногда и XML. Отступить к text/html если ничего другого не приемлемо.
  4. если (HTML) выплюнуть <HEAD> а также <NAV> (с учетом параметров: <h1>Black Cars</h1>)
  5. выкладывать результаты, используя наиболее приемлемый тип ответа.
    Эта функция знает, как взять объект результата SQL и превратить его в HTTP Link заголовки, поток HTML <LINK> элементы, HAL's _links ключ, поток элементов XLink, HTML <TABLE> элемент (с ячейками, содержащими <A> элементы), или файл CSV. Запрос SQL может возвращать 0 строк, в этом случае вместо таблицы HTML пишется удобное для пользователя сообщение, если этот вывод использовался.
  6. если (HTML) выплюнуть <FOOTER>

Эта базовая схема обрабатывает около 30 различных коллекций ресурсов в моем веб-приложении, хотя каждая из них имеет свой набор параметров, которые может вызывать URI запроса, поэтому начало каждой из них отличается с точки зрения проверки параметров.

Итак, теперь, когда я объяснил все это, вы можете увидеть, как может быть полезно, чтобы все особенности каждого ресурса обрабатывались в одном месте, а обобщенный вывод в формате X или формате Y обрабатывался общей библиотечной функцией. Это деталь реализации, которая облегчает мою жизнь и помогает мне придерживаться принципа "Не повторяйся".

Я определенно не согласен с подходом веб-сайта == веб-сервис.

Проще говоря, веб-сайт должен рассматриваться как клиент, просто клиент, который использует веб-сервис и отображает данные в соответствующей форме для веб-использования. Так же, как мобильное приложение - это клиент, просто клиент, использующий тот же веб-сервис и отображающий данные в подходящей форме для мобильного использования.

Веб-сервис является поставщиком услуг. Все остальные просто клиенты; веб-сайт, приложение для Android, приложение для iPhone,... и т. д.

Другие вопросы по тегам