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

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

Я создаю веб-сайт, а также хочу создать веб-службу REST для доступа к множеству одинаковых функций (с помощью движка google и spring mvc3), и я не уверен в лучших практиках того, как интегрированные/разделить 2 части должны быть.

Например, если я хочу просмотреть ресурс, я могу предоставить URL-адрес в форме:

{resourcetype}\{resourceid}

Запрос GET на этот URL-адрес может быть перенаправлен на представление, которое создает веб-страницу, когда клиент основан на HTML/браузере. spring имеет (из того, что я читал - еще не пробовал) возможность использовать этот же URL-адрес ресурса для представления представления, которое возвращает HTML/Xml/JSON в зависимости от типа содержимого. Все это кажется замечательным.

Запросы POST к URL-адресу для создания новых ресурсов в REST должны возвращать 201 СОЗДАН (или так я читаю) вместе с URL-адресом созданного ресурса, который кажется прекрасным для Api, но кажется немного отличным от того, что можно было бы ожидать от норма в веб-странице (где вы, вероятно, будете перенаправлены на страницу, показывающую созданный вами ресурс, или на страницу, в которой говорилось, что она была создана успешно или аналогично). Должен ли я обрабатывать это, обслуживая страницу с другим URL-адресом, который содержит форму для создания ресурса, затем отправляет URL-адрес Api через ajax и получает ответ и перенаправляет URL-адрес ресурса, включенный в ответ.

Этот шаблон кажется, что он будет работать (и должен работать и для DELETE), но это хороший подход, или я лучше сохраняю URL-адреса REST Api и URL-адреса веб-сайта отдельно? это похоже на то, что это может привести к кратковременному дублированию и дополнительной работе. Но наличие одного URL-адреса может означать, что вы зависите от javascript, доступного на клиенте поддерживающего HTML 5 браузера.

4b9b3361

Ответ 1

Я не согласен с ответом Майкла и использую его как основу для своего:

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

Если вы настаиваете на управлении версиями своего API, я бы попросил вас сделать это с использованием типа носителя, а не URI.

Далее, вы упрощаете свою реализацию. Теперь каждый метод не должен определять, запускается ли он JSON/XML или HTML.

Если вы делаете это так, вы делаете это неправильно. Исходя из Джерси, я возвращаю тот же проклятый объект из каждого метода, независимо от того, создаю ли я HTML, XML или JSON. Это полностью сквозная забота, о которой заботится маршаллер. Я использую VelocityMessageBodyWriter, чтобы испускать HTML-шаблоны, окружающие мои представления REST.

Каждый ресурс в моей системе следует тому же базовому поведению:

class FooResource extends Resource {
    @GET
    public FooRepresentation get() {
        return new FooRepresentation();
    }
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Response postForm(MulivaluedMap<String, String> form) {
        return post(buildRepresentationFromForm(form));
    }
    @POST
    @Consumes(MediaType.APPLICATION_XML)
    public Resopnse post(FooRepresentation representation) {
         // return ok, see other, whatever
    }
}

Для метода GET может потребоваться построить Ссылки для других ресурсов. Они используются потребителями REST API, а также HTML-шаблоном. Форма может иметь значение POST, и я использую определенную ссылку (определенную Relation) для атрибута "действие" ).

Путь через систему может быть разным между пользовательским браузером и пользовательским компьютером, но это не разделение реализации - it is REST! Передача состояния происходит так, как нужно, как вы ее определяете. Как работают пользователи (в браузере).

"Наконец, отделив сайт от API, вы разрешаете различные требования к масштабированию. Если ваш API сильно пострадает, но не веб-сайт, вы можете бросить больше аппаратного обеспечения в API, сохраняя при этом минимальные требования к веб-сайту." - ваше масштабирование не должно зависеть от того, кто использует то, что здесь. Скорее всего, вы занимаетесь какой-то работой за кулисами, которая более интенсивна, чем просто показ HTML. Используя ту же реализацию, масштабирование еще проще. Сам API (маршалинг между XML и объектами домена и обратно) не будет превышать бизнес-логику и обработку, базу данных и т.д.

Наконец, сохраняя их одинаково, гораздо проще думать о вашей системе в целом. На самом деле, начните с HTML. Определите отношения. Если вам сложно определить конкретное действие или историю пользователей в анкерах и формах HTML, вы, вероятно, отклонились от REST.

Помните, что вы выражаете вещи как ссылки (определенного отношения) к другим вещам. Эти URI могут даже отличаться в зависимости от того, производят ли вы XML или HTML - HTML-страница может POST для URI some/uri/a, и API может использовать POST для некоторого /uri/b - это не имеет значения и касается того, что фактическое Содержимое URI - это темный путь к POX и RPC

Еще одна отличная особенность заключается в том, что если вы это сделаете, вы не будете зависеть от JavaScript. Вы определили, что ваша система работает с базовым HTML, и вы можете "переворачивать" JavaScript, когда он доступен. Тогда вы действительно работаете со своим "API" в любом случае (я сжимаю, ссылаясь на них как на разные вещи, но я также пытаюсь свести свой ответ к вашей формулировке).

** Я добавлю один последний комментарий, при создании HTML я использую 303 вместо 201, чтобы облегчить POST-then-GET. Если JS включен, вы фактически говорите об XML (или JSON), и вы вернетесь к 201.

Ответ 2

Я предлагаю вам держать их отдельно. Делая это, вы получаете несколько преимуществ.

Во-первых, вы отделите свои URL-адреса от своих URL-адресов API, чтобы каждый из них мог изменять самостоятельно. Например, вам может потребоваться отменить обратно несовместимые изменения в ваш API, и в этом случае вы можете создать каталог /v 2/. Между тем, вам может понадобиться страница /about на веб-сайте, но она не нужна для вашего API.

Используя разные URL-адреса, вы упрощаете свою реализацию. Теперь каждый метод не должен определять, идет ли он с JSON/XML или HTML. Это верно, даже если у вас есть фреймворк вроде Spring, делающий тяжелый подъем; у вас все еще есть дополнительные вещи для веб-сайта в отношении текущего пользователя.

Он также устраняет целый класс ошибок. Например, пользователи не будут получать выходные данные JSON или XML во время просмотра сайта, даже если у них есть пользовательские настройки анонимности браузера.

Вы можете легко разделить логику аутентификации. На веб-сайте вам нужна страница входа и файлы cookie. С API они не требуются, но дополнительные заголовки аутентификации (например, подпись HMAC + sha256).

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


Update: Чтобы уточнить, я не предлагаю вам код всего дважды. Существует два способа взглянуть на это, чтобы удалить дублирование.

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

Еще один способ взглянуть на это - ваш сайт является вашим первым клиентом вашего публичного API REST; веб-сервер на самом деле вызывает ваш RESTful API для получения информации. Это принцип "Ешьте свой собственный корм для собак".

Ответ 3

В поддержку Майкла, и в отличие от Дуга, вы должны держать их в стороне.

Оказывается, браузер в его базовой форме не является особенно хорошим клиентом REST. Из-за отсутствия полной поддержки HTTP, от ложной поддержки аутентификации, до слабой поддержки типов медиа, браузер на самом деле довольно ограничен. Если вы ограничены просто потребляющим контентом, а этот контент - HTML, то браузер в порядке, но выходит за рамки этого, и API страдает от плохой поддержки в браузере.

JavaScript может улучшить возможности браузера и сделать его лучшим гражданином REST, но мало что работает в браузере, чем статическая HTML-страница. Портативный, эффективный, масштабируемый для разных устройств с некоторым удовольствием от CSS. Все любят привязку к статической странице, особенно к той, на которой не размещаются изображения на миллион, и что не из других медленных поставщиков. Нажмите кнопку BANG, быстро появляющуюся, быструю прокручиваемую страницу.

Поскольку браузер - грустный гражданин, вы не должны ограничивать свой API слабыми возможностями. Разделив их, вы можете написать приятный, богатый, анимированный, насыщенный, захватывающий интерфейс в HTML + JS или Flash, Java, Obj-C для iOS или Android или что угодно.

Вы также можете написать приятный интерфейс на PHP, размещенный на вашем сервере, и вывод результатов в браузеры. PHP-приложение не обязательно должно быть REST вообще, это может быть просто общее веб-приложение, работающее в домене и ограничения веб-приложения (сеансы с состоянием, не-семантическая разметка и т.д.). Браузер разговаривает с PHP, PHP разговаривает с вашим сервисом REST. Приложение PHP позволяет отделить требования браузера от семантики службы REST.

Вы можете писать более HTML-приложения RESTful, даже с чистым HTML. Они просто оказываются довольно мутными приложениями, которые люди не любят использовать.

Очевидно, существует много возможных совпадений между общим веб-приложением и службой REST, но перекрытие - это не равенство, и они разные. HTTP!= REST, используя HTTP, не означает, что вы используете REST. HTTP хорошо подходит для приложений REST, но вы, безусловно, можете использовать HTTP в не-RESTful способах. Люди делают это весь день.

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

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

Addenda:

Сэм -

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

И это логическое разделение, независимо от того, что проявляется в шаблонах URL-адресов, у меня нет мнения. Это больше вызовов разработки/обслуживания/развертывания. Я нахожу, что логическое разделение, которое может проявляться физически, имеет некоторые преимущества с точки зрения ясности и понимания, но что я.

Дуг -

Необработанный пользовательский интерфейс HTML является сложным. Если бы это было не так, то не было бы всей индустрии, окружающей, чтобы приложение пользовательского браузера не искажалось. Конечно, он может быть функциональным, и использование HTML - отличный медиа-тип для приложений REST. ИЗМЕНЕНИЕ инструментария вокруг браузеров и, таким образом, работа с интерфейсом, просмотр артефактов, взаимодействие с сервисом, когда это возможно, легче сделать. Но вы не разрабатываете свой API-интерфейс службы вокруг своего отладчика, а необработанный браузер - это неполный инструмент для полного использования HTTP. Как хост для JS через XHR, он становится более способным, но теперь мы говорим "богатый клиент", а не просто прямой HTML в браузере.

Хотя вы можете сделать POST-фасады служб для удаления и других, как в вашем примере, единственная причина, по которой вы это делаете, связана с ограничениями браузера, а не ради самого API. Если что-то это загромождает и усложняет API. "Несколько способов сделать это".

Теперь, очевидно, вы можете туннелировать все через POST, просто потому, что вам нравится туннелировать все через POST. Но, скрывая это, вы обходите другие аспекты протокола. Если вы POST foo/1 to/deleteFoos, вы не сможете использовать такие вещи, как кеши и т.д. УДАЛЕНИЕ на foo/1 приведет к аннулированию любых кэшей, которые видят операцию, но POST проскользнет прямо, оставив старый, теперь удаленный ресурс.

Итак, есть причины, почему в протоколе есть другие глаголы, чем POST и GET, даже если родной браузер предпочитает не использовать их.

Ответ 4

Я думаю, что вам разумно требовать javascript, чтобы вы могли использовать методы ajax, чтобы делать то, что вы предложили в третьем абзаце вашего вопроса.

Кроме того, чтобы уточнить, независимо от того, использует ли клиент заголовок местоположения ответа 201 для указания канонического URI вновь созданного ресурса. Они могут быть проверены вашим javascript для клиентов, которые его используют.

О "dumber" клиентах (например: в браузере с отключенным js), несколько уродливый способ заставить их сделать переадресацию, чтобы иметь мета-обновление html в разделе заголовка возвращаемого ресурса html из POST. Затем тело ответа может просто кратко описать ваш новый ресурс, пока вы используете заголовок Location.