Ух ты, поэтому этот ответ быстро обострился ...
За последний год или около того я пытался лучше понять REST с помощью книг, списков рассылки и т. Д. По какой-то причине я решил выбрать ваш вопрос в качестве теста того, что я узнал.
Извините: P
Давайте упростим весь этот пример. Вместо того, чтобы беспокоиться о загрузке файла пользователем, мы будем предполагать, что пользователь просто передает строку. Так что, на самом деле, они собираются передать строку в дополнение к аргументам символов для замены (список ключей / значений). О загрузке файлов мы поговорим позже.
Вот RESTful способ сделать это, который не требует ничего, чтобы быть сохраненным на сервере. Я буду использовать некоторый HTML-код (хотя и неработающий, но опущу такие вещи, как HEAD) в качестве медиа-типа, просто потому, что он довольно хорошо известен.
Пример решения
Во-первых, пользователю необходимо получить доступ к нашей службе REST.
GET /
<body>
<a rel="http://example.com/rels/arguments" href="/arguments">
Start Building Arguments
</a>
</body>
По сути, это дает пользователю возможность начать фактически взаимодействовать с нашим сервисом. Прямо сейчас у них есть только один вариант: использовать ссылку для создания нового набора аргументов (пары имя / значение, которые в конечном итоге будут использоваться в схеме замены строк). Таким образом, пользователь переходит по этой ссылке.
GET / arguments
<body>
<a rel="self" href="/arguments"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}">
<input id="input_string" name="input_string" />
</form>
</body>
Это приводит нас к экземпляру ресурса "arguments". Обратите внимание, что это не документ JSON или XML, который возвращает вам просто простые данные пар ключ / значение; это гипермедиа. Он содержит элементы управления, которые направляют пользователя к тому, что он может делать дальше (иногда упоминается как разрешение пользователю «следовать за своим носом»). Этот конкретный URL ("/ arguments") представляет собой пустой список пар ключ / значение. Я мог бы очень хорошо назвать URL-адрес «/ empty_arguments», если бы захотел: это пример, почему глупо думать о REST с точки зрения URL-адресов: это действительно не должно иметь значения, что такое URL.
В этом новом HTML пользователю предоставляется три различных ресурса, по которым он может перемещаться:
- Они могут использовать ссылку "self", чтобы перейти к тому же ресурсу, на котором они в данный момент находятся.
- Они могут использовать первую форму для перехода к новому ресурсу, который представляет список аргументов с дополнительным сочетанием имя / значение, которое они указывают в форме.
- Они могут использовать вторую форму, чтобы предоставить строку, на которой они хотят, наконец, выполнить замену.
Примечание: вы, вероятно, заметили, что вторая форма имеет странный URL "действия":
/arguments?{key}={value}
Здесь я обманул: я использую URI Templates . Это позволяет мне указать, как аргументы будут размещаться на URL-адресе, а не использовать стандартную HTML-схему, состоящую только из <input-name>=<input-value>
. Очевидно, что для того, чтобы это работало, пользователь не может использовать браузер (поскольку браузеры этого не реализуют): ему нужно будет использовать программное обеспечение, которое понимает HTML и URI-шаблонизаторы. Конечно, я использую HTML в качестве примера, ваш REST-сервис может использовать какой-то XML, который поддерживает URI Templating, как определено в спецификации URI Template.
В любом случае, допустим, пользователь хочет добавить свои аргументы. Пользователь использует первую форму (например, заполняя ввод «ключ» с помощью «Автор» и ввод «значение» с «Джон Доу»). Это приводит к ...
GET / arguments? Author = John% 20Doe
<body>
<a rel="self" href="/arguments?Author=John%20Doe"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
Теперь это совершенно новый ресурс. Вы можете описать его как список аргументов (пары ключ / значение) с одной парой ключ / значение: «Автор» / «Джон Доу». HTML-код практически такой же, как и раньше, с некоторыми изменениями:
- Ссылка "self" теперь указывает на URL текущих ресурсов (изменен с "/ arguments" на "/ arguments? Author = John% 20Doe"
- Атрибут «action» первой формы теперь имеет более длинный URL, но мы снова используем шаблоны URI, чтобы позволить нам создать больший URI.
- Вторая форма
Теперь пользователь хочет добавить аргумент «Дата», чтобы он снова отправил первую форму, на этот раз с ключом «Дата» и значением «2003-01-02».
GET / arguments? Author = John% 20Doe & Date = 2003-01-02
<body>
<a rel="self" href="/arguments?Author=John%20Doe&Date=2003-01-02"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&Date=2003-01-02&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
Наконец, пользователь готов обработать свою строку, поэтому он использует вторую форму и заполняет переменную "input_string".Это снова использует шаблоны URI, таким образом приводя пользователя к следующему ресурсу.Допустим, строка выглядит следующим образом:
{Author} wrote some books in {Date}
Результаты будут такими:
GET / processing_string /% 7BAuthor% 7D + wrote + некоторые + книги+ in +% 7BDate% 7D? Автор = Джон% 20Doe & Дата = 2003-01-02
<body>
<a rel="self" href="/processed_string/%7BAuthor%7D+wrote+some+books+in+%7BDate%7D?Author=John%20Doe&Date=2003-01-02">
<span class="results">John Doe wrote some books in 2003-01-02</span>
</body>
PHEW!Это много работы!Но это (AFAIC) RESTful, и оно отвечает требованию отсутствия необходимости хранить НИЧЕГО на стороне сервера (включая список аргументов или строку, которую вы в конечном итоге захотите обработать).
Важные замечания, на которые стоит обратить внимание
Здесь важно то, что я не просто говорил об URL.На самом деле, большую часть времени я говорю о HTML.HTML - это гипермедиа, это такая огромная часть REST, о которой забывают.Все те API, которые говорят, что они «спокойны», когда говорят «сделать GET по этому URL с этими параметрами и POST по этому URL с документом, который выглядит так», не практикуют REST.Рой Филдинг (который буквально написал книгу о REST ) сам сделал это наблюдение .
Еще одна вещь, которую стоит отметить, это то, что просто было довольно сложно задаватьдо аргументов.После того, как начальный GET / попадет в корень (вы можете думать об этом как о «меню») службы, вам нужно будет выполнить еще пять вызовов GET, просто чтобы создать свой ресурс аргумента, чтобы сделать ресурс аргумента из четырех ключей./ пары значений.Это можно облегчить, если не использовать HTML.Например, я уже использовал шаблоны URI в моем примере, нет никаких оснований утверждать, что HTML просто недостаточно хорош для REST.Используя гипермедиа формат (например, некоторое наследование XML), который поддерживает нечто похожее на формы, но с возможностью указывать «сопоставления» значений, вы можете сделать это за один раз.Например, мы могли бы расширить тип носителя HTML, чтобы разрешить другой тип ввода, называемый «сопоставления» ...
Пока клиент, использующий наш API, понимает, что такое тип ввода «сопоставления», он сможетдля создания ресурса их аргументов с помощью одного GET.
В этот момент вам может даже не потребоваться ресурс «аргументы».Вы могли бы просто перейти прямо к ресурсу «processing_string», который содержит отображение и фактическую строку ...
А как насчет загрузки файла?
Хорошо, поэтому изначально вы упомянули загрузку файлов и какчтобы получить это без необходимости хранить файл.Ну, в принципе, мы можем использовать наш существующий пример, но заменим последний шаг файлом.
Здесь мы в основном делаем то же самое, что и раньше, за исключением того, что мы загружаем файл.Важно отметить, что теперь мы намекаем пользователю (через атрибут «method» в форме), что он должен выполнить POST, а не GET.Обратите внимание, что хотя везде вы слышите, что POST является небезопасной (она может вызвать изменения на сервере), неидемпотентной операцией, ничто не говорит о том, что это ДОЛЖНО быть изменение состояния на сервере.
Наконецсервер может вернуть новый файл (еще лучше было бы вернуть какой-нибудь гипермедиа или заголовок LOCATION со ссылкой на новый файл, но это потребовало бы хранения).
Заключительные комментарии
Этоэто всего лишь один пример этого конкретного примера.Хотя я надеюсь, что вы получили какое-то понимание, я бы предостерег вас принять это как Евангелие.Я уверен, что были вещи, которые я сказал, которые на самом деле не "ОТДЫХ".Я планирую опубликовать этот вопрос и ответить на REST-Discuss рассылки и посмотреть, что другие скажут об этом.
Одна из главных вещей, которую я хотел бы выразить, заключается в том, что самым простым решением может быть просто использование RPC.В конце концов, какова была ваша первоначальная попытка сделать RESTful-попытку?Если вы пытаетесь сказать людям, что выполняете «REST», имейте в виду, что многие API заявили о себе как «RESTful», которые на самом деле были просто замаскированы RPC URL-адресами с существительными, а не с глаголами.
Если это произошло из-за того, что вы узнали о некоторых преимуществах REST и о том, как получить эти преимущества неявно, сделав свой API RESTful, досадная истина в том, что в REST есть нечто большее, чем URL, и независимо от того, ПОЛУЧАЕТЕ или ПОСТАВЛЯЕТЕ их.Гипермедиа играет огромную роль.
Наконец, иногда вы сталкиваетесь с проблемами, которые могут означать, что вы можете делать вещи, которые НЕ ПОЛУЧАЮТ RESTful.Возможно, вам нужно сделать POST, а не GET, потому что URI (который имеет теоретический бесконечный объем памяти, но множество технических ограничений) будет слишком длинным.Ну, тогда вам нужно сделать POST.Может быть
Дополнительные ресурсы: