Понимание REST: глаголы, коды ошибок и аутентификация

602

Я ищу способ обернуть API-интерфейсы вокруг функций по умолчанию в моих веб-приложениях на базе PHP, базах данных и CMS.

Я осмотрелся и нашел несколько «каркасных» рамок. В дополнение к ответам на мой вопрос есть Tonic , REST Framework, который мне нравится, потому что он очень легкий.

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

1. Я правильно понимаю?

Скажем, у меня есть ресурс "пользователи". Я мог бы установить несколько URI, например, так:

/api/users     when called with GET, lists users
/api/users     when called with POST, creates user record
/api/users/1   when called with GET, shows user record
               when called with PUT, updates user record
               when called with DELETE, deletes user record

это правильное представление архитектуры RESTful до сих пор?

2. Мне нужно больше глаголов

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

Вот некоторые примеры, которые приходят на ум в пользовательском примере:

activate_login
deactivate_login
change_password
add_credit

Как бы я выразил действия, такие как в архитектуре RESTful URL?

Мой инстинкт должен был бы сделать вызов GET к URL, как

/api/users/1/activate_login 

и ожидать код состояния обратно.

Это отличается от идеи использования HTTP-глаголов. Что вы думаете?

3. Как вернуть сообщения об ошибках и коды

Большая часть красоты REST связана с использованием стандартных методов HTTP. При ошибке я выдаю заголовок с кодом ошибки 3xx, 4xx или 5xx. Для подробного описания ошибки я могу использовать тело (правильно?). Все идет нормально. Но как можно было бы передать собственный код ошибки , более подробно описывающий, что пошло не так (например, «не удалось подключиться к базе данных» или «неверный вход в базу данных»)? Если я добавлю его в тело вместе с сообщением, мне придется потом разобрать его. Есть ли стандартный заголовок для такого рода вещей?

4. Как сделать аутентификацию

  • Как будет выглядеть аутентификация на основе ключа API в соответствии с принципами REST?
  • Есть ли сильные стороны против использования сессий при аутентификации клиента REST, кроме того, что это явное нарушение принципа REST? :) (шутка здесь только наполовину, аутентификация на основе сеанса будет хорошо сочетаться с моей существующей инфраструктурой.)
Пекка
источник
13
@ Дэниел, спасибо за редактирование. «У меня больше глаголов» было намеренным каламбуром, но я оставляю все как есть, теперь легче читать. :)
Пекка
1
Кстати, об описании ошибки. В итоге я поместил описание ошибки в заголовок ответа. Просто добавьте заголовок с именем «Описание ошибки».
Андрей Музычук
Это больше похоже на вопросы безопасности приложения. Безопасность приложения - это не то, что нужно REST.
Назар Мерза
@NazarMerza как вопросы безопасности приложений 1., 2. и 3.?
Пекка

Ответы:

621

Я заметил этот вопрос на пару дней позже, но я чувствую, что могу добавить немного понимания. Я надеюсь, что это может быть полезно для вашего RESTful предприятия.


Пункт 1: я правильно понимаю?

Вы правильно поняли. Это правильное представление архитектуры RESTful. Вы можете найти следующую матрицу из Википедии очень полезной для определения ваших существительных и глаголов:


При работе с Collection URI, например:http://example.com/resources/

  • ПОЛУЧИТЬ : список членов коллекции, вместе с их URI членов для дальнейшей навигации. Например, список всех автомобилей на продажу.

  • PUT : значение, определенное как «заменить всю коллекцию другой коллекцией».

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

  • DELETE : значение, определенное как «удалить всю коллекцию».


При работе с членом URI, как:http://example.com/resources/7HOU57Y

  • GET : получить представление адресованного члена коллекции, выраженное в соответствующем типе MIME.

  • PUT : обновить указанный элемент коллекции или создать его с указанным идентификатором.

  • POST : рассматривает адресуемый член как коллекцию самостоятельно и создает нового подчиненного.

  • УДАЛИТЬ : Удалить указанного члена коллекции.


Пункт 2: мне нужно больше глаголов

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

Активировать / деактивировать вход в систему : если вы создаете новый сеанс, вы можете рассмотреть «сеанс» как ресурс. Чтобы создать новый сеанс, используйте POST для http://example.com/sessions/с учетными данными в теле. Чтобы истечь, используйте PUT или DELETE (возможно, в зависимости от того, хотите ли вы сохранить историю сеансов) http://example.com/sessions/SESSION_ID.

Изменить пароль: на этот раз ресурс «пользователь». Вам потребуется PUT http://example.com/users/USER_IDсо старыми и новыми паролями в теле. Вы действуете на «пользовательском» ресурсе, а изменение пароля - это просто запрос на обновление. Это очень похоже на оператор UPDATE в реляционной базе данных.

Мой инстинкт должен был бы сделать вызов GET к URL, как /api/users/1/activate_login

Это противоречит основному принципу REST: правильному использованию глаголов HTTP. Любой запрос GET никогда не должен оставлять никаких побочных эффектов.

Например, запрос GET никогда не должен создавать сеанс в базе данных, возвращать cookie с новым идентификатором сеанса или оставлять какие-либо остатки на сервере. Глагол GET похож на оператор SELECT в ядре базы данных. Помните, что ответ на любой запрос с глаголом GET должен быть доступен для кэширования при запросе с теми же параметрами, как и при запросе статической веб-страницы.


Пункт 3: Как вернуть сообщения об ошибках и коды

Рассматривайте коды состояния HTTP 4xx или 5xx как категории ошибок. Вы можете разработать ошибку в теле.

Не удалось подключиться к базе данных: / Неправильный вход в базу данных : как правило, вы должны использовать 500 ошибок для этих типов ошибок. Это ошибка на стороне сервера. Клиент не сделал ничего плохого. 500 ошибок обычно считаются «повторяющимися». т. е. клиент может повторить тот же самый точный запрос и ожидать, что он будет успешным после устранения проблем сервера. Укажите детали в теле, чтобы клиент мог предоставить нам некоторый контекст для нас, людей.

Другой категорией ошибок будет семейство 4xx, которое в целом указывает на то, что клиент сделал что-то не так. В частности, эта категория ошибок обычно указывает клиенту, что нет необходимости повторять запрос, как он есть, потому что он будет продолжать сбой постоянно. т.е. клиент должен что-то изменить, прежде чем повторить этот запрос. Например, ошибки «Ресурс не найден» (HTTP 404) или «Неверный запрос» (HTTP 400) попадают в эту категорию.


Пункт 4: Как сделать аутентификацию

Как указано в пункте 1, вместо аутентификации пользователя вы можете подумать о создании сеанса. Вам будет возвращен новый «идентификатор сеанса» вместе с соответствующим кодом состояния HTTP (200: доступ разрешен или 403: доступ запрещен).

Затем вы спросите свой сервер RESTful: «Можете ли вы ПОЛУЧИТЬ мне ресурс для этого идентификатора сеанса?».

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

Даниэль Вассалло
источник
6
Очень хорошо, однако вы, PUTвероятно, неправильно использовали пароль для изменения пароля; PUTтребуется весь ресурс, поэтому вам нужно будет отправить все пользовательские атрибуты, чтобы соответствовать HTTP (и, следовательно, HATEOAS REST). Скорее, чтобы просто изменить пароль, нужно использовать PATCHили POST.
Лоуренс Дол
1
Я думаю, что этот пост был бы идеальным, если бы вы более подробно остановились на том, что «POST: рассматривает адресуемый элемент как отдельную коллекцию и создает его нового подчиненного». средства. - Я понял, что значит «гуглить» - это исключение из твоего отличного ответа.
Мартин Конечни
6
Я не согласен с самым последним предложением. Вы объясняете, как REST не имеет состояния. Вход в систему для создания сеанса, а затем выход из системы для завершения сеанса после выполнения некоторой работы - лучший пример API с сохранением состояния.
Брэндон
1
«Это противоречит основному принципу REST: правильному использованию HTTP-глаголов. Любой запрос GET никогда не должен оставлять никаких побочных эффектов». - Что делать, если вы хотите сохранить количество посещений для ресурса?
bobbyalex
1
Эта статья должна ответить на ваши вопросы. saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices
java_geek
79

Проще говоря, вы делаете это полностью назад.

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

Цитировать Роя Филдинга

API-интерфейс REST должен потратить почти все свои описательные усилия на определение типов носителей, используемых для представления ресурсов и управления состоянием приложения, или на определение имен расширенных отношений и / или разметки с поддержкой гипертекста для существующих стандартных типов носителей. Любое усилие, затрачиваемое на описание того, какие методы использовать с какими интересующими URI, должно быть полностью определено в рамках правил обработки для типа носителя (и, в большинстве случаев, уже определено существующими типами носителя). [Ошибка здесь подразумевает, что внешняя информация является движущей силой взаимодействия, а не гипертекста.]

Люди всегда начинают с URI и думают, что это решение, а затем они, как правило, упускают ключевую концепцию в архитектуре REST, в частности, как указано выше: «Ошибка здесь подразумевает, что внеполосная информация управляет взаимодействием, а не гипертекстом. "

Если честно, многие видят кучу URI и некоторые GET, PUT и POST и думают, что REST - это легко. ОТДЫХ не легко. RPC через HTTP - это просто, перемещение больших объемов данных назад и вперед по прокси через полезные нагрузки HTTP очень просто. Отдых, однако, выходит за рамки этого. REST не зависит от протокола. HTTP просто очень популярен и подходит для систем REST.

REST живет в типах носителей, их определениях и в том, как приложение управляет действиями, доступными для этих ресурсов через гипертекст (ссылки, эффективно).

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

Я думаю, что оба подхода имеют свое место: XHTML очень хорошо работает в сценариях, которые перекрывают как управляемую человеком, так и управляемую машиной сеть, тогда как первые, более конкретные типы данных, которые я чувствую лучше, облегчают взаимодействие между машинами. Я считаю, что подъем товарных форматов может сделать переговоры о контенте потенциально трудными. «application / xml + yourresource» гораздо более специфичен как тип носителя, чем «application / xhtml + xml», поскольку последний может применяться ко многим полезным нагрузкам, которые могут или не могут быть чем-то, что на самом деле интересует клиент машины, и не может определить без самоанализа.

Тем не менее, XHTML работает очень хорошо (очевидно) в человеческой сети, где веб-браузеры и рендеринг очень важны.

Ваша заявка поможет вам в принятии таких решений.

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

Напомним, что каждое представление ресурса в гипертекстовой системе объединяет как фактическое представление ресурса, так и переходы состояний, доступные для ресурса. Рассмотрим каждый ресурс как узел в графе, со ссылками, являющимися линиями, выходящими из этого узла в другие состояния. Эти ссылки информируют клиентов не только о том, что можно сделать, но и о том, что для них требуется (так как хорошая ссылка сочетает в себе URI и требуемый тип носителя).

Например, вы можете иметь:

<link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>

Ваша документация расскажет о поле rel, названном «users», и о типе носителя «application / xml + youruser».

Эти ссылки могут показаться излишними, все они в основном разговаривают с одним и тем же URI. Но это не так.

Это связано с тем, что для отношения «пользователи» эта ссылка говорит о коллекции пользователей, и вы можете использовать унифицированный интерфейс для работы с коллекцией (GET для получения всех из них, DELETE для удаления всех из них и т. Д.)

Если вы отправляете POST по этому URL, вам нужно будет передать документ «application / xml + usercollection», который, вероятно, будет содержать только один экземпляр пользователя в документе, так что вы можете добавить пользователя или, возможно, добавить несколько в один раз. Возможно, ваша документация предполагает, что вы можете просто передать один тип пользователя вместо коллекции.

Вы можете увидеть, что требуется приложению для выполнения поиска, как определено ссылкой «поиск» и ее медиатипом. Документация по поисковому типу мультимедиа расскажет вам, как это ведет себя, и что ожидать в результате.

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

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

Эти две ссылки семантически идентичны в глазах клиентов:

<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
<link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>

Итак, сосредоточьтесь на своих ресурсах. Сосредоточьтесь на их переходах состояний в приложении и на том, как это лучше всего достигается.

Уилл Хартунг
источник
1
Спасибо Уилл за этот очень глубокий ответ. Несколько очков принято. Я понимаю, что планирование «как выглядит URL» делает это наоборот, и я планирую и со стороны ресурсов. Наличие URL-адресов для игры упрощает понимание этой концепции. Это может быть , что мои требования могут быть удовлетворены с помощью системы , которая не 100% принципы последующей REST , как вы определяете его здесь. Я составлю полный список требований для каждого типа ресурса, думаю, тогда я смогу принять решение. Приветствия.
Пекка
30

ре 1 : Это выглядит хорошо до сих пор. Не забудьте вернуть URI вновь созданного пользователя в заголовке «Location:» как часть ответа на POST вместе с кодом состояния «201 Created».

Re 2Активация через GET - плохая идея, и включение глагола в URI - запах дизайна. Вы можете рассмотреть вопрос о возвращении формы на GET. В веб-приложении это будет HTML-форма с кнопкой отправки; в случае использования API вы можете вернуть представление, содержащее URI для PUT, чтобы активировать учетную запись. Конечно, вы также можете включить этот URI в ответ на POST для / users. Использование PUT гарантирует, что ваш запрос идемпотентен, то есть его можно безопасно отправить снова, если клиент не уверен в успехе. В общем, подумайте о том, в какие ресурсы вы можете превратить свои глаголы (своего рода «обозначение глаголов»). Спросите себя, с каким методом ваши конкретные действия наиболее тесно связаны. Например, change_password -> PUT; деактивировать -> возможно УДАЛИТЬ; add_credit -> возможно POST или PUT.

3. Не изобретайте новые коды состояния, если только вы не уверены, что они настолько универсальны, что заслуживают стандартизации во всем мире. Старайтесь использовать наиболее подходящий код состояния (читайте обо всех из них в RFC 2616). Включите дополнительную информацию в тело ответа. Если вы действительно уверены, что хотите изобрести новый код состояния, подумайте еще раз; если вы все еще верите в это, убедитесь, что вы выбрали хотя бы правильную категорию (1xx -> OK, 2xx -> информационное, 3xx -> перенаправление; 4xx-> ошибка клиента, 5xx -> ошибка сервера). Я упоминал, что изобретать новые коды статуса - плохая идея?

4. Если возможно, используйте встроенную в HTTP инфраструктуру аутентификации. Проверьте, как Google выполняет аутентификацию в GData. В общем, не помещайте ключи API в ваши URI. Старайтесь избегать сеансов для повышения масштабируемости и поддержки кэширования - если ответ на запрос отличается из-за чего-то, что произошло раньше, вы обычно привязываете себя к конкретному экземпляру процесса сервера. Гораздо лучше превратить состояние сеанса либо в состояние клиента (например, сделать его частью последующих запросов), либо сделать его явным, превратив его в состояние (сервера) ресурса, то есть присвоить ему собственный URI.

Стефан Тилков
источник
Можете ли вы обсудить, почему не помещать ключи API в URL? Это потому что они видны в логах прокси? Что если ключи временные, основанные на времени? Что делать, если используется HTTPS?
MikeSchinkel
4
Помимо нарушения духа (URI должны идентифицировать вещи), главное последствие состоит в том, что он разрушает кеширование.
Стефан Тилков
22

1. У вас есть правильное представление о том, как проектировать свои ресурсы, ИМХО. Я бы не стал ничего менять.

2. Вместо того, чтобы пытаться расширить HTTP с помощью большего количества глаголов, рассмотрите, к чему могут быть сокращены ваши предложенные глаголы, с точки зрения основных методов и ресурсов HTTP. Например, вместо activate_loginглагола вы можете настроить такие ресурсы, как: /api/users/1/login/activeкоторый является простым логическим значением. Чтобы активировать логин, просто PUTдокумент там, который говорит «true» или 1 или что-то еще. Для деактивации PUTтам есть пустой документ, в котором указано 0 или false.

Точно так же, чтобы изменить или установить пароли, просто сделайте PUTs для /api/users/1/password.

Всякий раз, когда вам нужно что-то добавить (например, кредит), думать с точки зрения POSTс. Например, вы можете сделать POSTдля ресурса, например, /api/users/1/creditsс телом, содержащим количество кредитов для добавления. A PUTна том же ресурсе можно использовать для перезаписи значения, а не для добавления. А POSTс отрицательным числом в теле вычтут и тд.

3. Я бы настоятельно рекомендовал не расширять базовые коды состояния HTTP. Если вы не можете найти тот, который точно соответствует вашей ситуации, выберите ближайший и поместите детали ошибки в теле ответа. Также помните, что HTTP-заголовки являются расширяемыми; Ваше приложение может определить все пользовательские заголовки, которые вам нравятся. Например, одно приложение, над которым я работал, могло возвращать 404 Not Foundпри нескольких обстоятельствах. Вместо того, чтобы заставлять клиента анализировать тело ответа по этой причине, мы просто добавили новый заголовок X-Status-Extended, который содержал наши собственные расширения кода состояния. Таким образом, вы можете увидеть ответ вроде:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

Таким образом, HTTP-клиент, такой как веб-браузер, по-прежнему будет знать, что делать с обычным кодом 404, а более сложный HTTP-клиент может посмотреть в X-Status-Extendedзаголовке более конкретную информацию.

4. Для аутентификации я рекомендую использовать HTTP-аутентификацию, если можете. Но IMHO, нет ничего плохого в использовании аутентификации на основе файлов cookie, если это проще для вас.

friedo
источник
4
Идеальная идея использования «расширенных» ресурсов для работы с меньшими порциями более крупного ресурса.
Уомбл
1
Cookies действительны в HTTP / REST, но сервер не должен хранить cookie как состояние (а не как сеанс). Однако cookie может хранить значение, подобное HMAC, которое можно разобрать, не просматривая состояние в другом месте.
Брюс Олдерсон
14

Основы ОТДЫХА

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

Таким образом, существует контракт между клиентом REST и сервисом REST. Если вы используете HTTP в качестве базового протокола, то в контракт входят следующие стандарты:

  • HTTP 1.1
    • определения методов
    • определения кода состояния
    • заголовки управления кешем
    • принимать и заголовки типа контента
    • оригинальные заголовки
  • IRI (UTF8 URI )
  • тело (выбрать одно)
    • тип MIME для определенного приложения, например, maze + xml
    • MIME-тип, специфичный для поставщика, например, vnd.github + json
    • универсальный тип MIME с
      • Vabab RDF для конкретного приложения, например, ld + json & hydra , schema.org
      • профиль конкретного приложения, например, hal + json и параметр ссылки на профиль (я думаю)
  • гиперссылок
    • что должно содержать их (выберите один)
      • отправка в заголовках ссылок
      • отправка гипермедиа-ответа, например, html, atom + xml, hal + json, ld + json & hydra и т. д.
    • семантика
      • использовать отношения ссылок IANA и, возможно, пользовательские отношения ссылок
      • использовать специфический для приложения словарь RDF

REST имеет ограничение без сохранения состояния, которое объявляет, что связь между службой REST и клиентом должна быть без сохранения состояния. Это означает, что служба REST не может поддерживать состояния клиента, поэтому у вас не может быть хранилища сеансов на стороне сервера. Вы должны аутентифицировать каждый запрос. Так, например, базовая аутентификация HTTP (часть стандарта HTTP) в порядке, поскольку она отправляет имя пользователя и пароль при каждом запросе.

Ответить на ваши вопросы

  1. Да, это может быть.

    Следует отметить, что клиенты не заботятся о структуре IRI, они заботятся о семантике, потому что они следуют по ссылкам, имеющим атрибуты отношений ссылок или связанных данных (RDF).

    Единственное, что важно в IRI, это то, что один IRI должен идентифицировать только один ресурс. Разрешено одному ресурсу, например пользователю, иметь много разных IRI.

    Это довольно просто, почему мы используем такие хорошие IRI, как /users/123/password; гораздо проще написать логику маршрутизации на сервере, когда вы понимаете IRI, просто читая его.

  2. У вас есть больше глаголов, таких как PUT, PATCH, OPTIONS и даже больше, но вам не нужно больше их ... Вместо того, чтобы добавлять новые глаголы, вы должны научиться добавлять новые ресурсы.

    activate_login -> PUT /login/active true deactivate_login -> PUT /login/active false change_password -> PUT /user/xy/password "newpass" add_credit -> POST /credit/raise {details: {}}

    (Вход в систему не имеет смысла с точки зрения REST из-за ограничения без сохранения состояния.)

  3. Ваши пользователи не заботятся о том, почему проблема существует. Они хотят знать только, есть ли успех или ошибка, и, возможно, сообщение об ошибке, которое они могут понять, например: «Извините, но мы не смогли сохранить ваше сообщение.» И т. Д ...

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

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

    Сторонний клиент получает токен доступа, если пользователь предоставляет ему доступ с помощью основного клиента. После этого сторонний клиент отправляет токен доступа при каждом запросе. Существуют более сложные решения, например, вы можете подписать каждый запрос и т. Д. Для получения более подробной информации обратитесь к руководству OAuth.

Сопутствующая литература

inf3rno
источник
11

Для приведенных вами примеров я бы использовал следующее:

activate_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

изменить пароль

PUT /passwords (предполагается, что пользователь аутентифицирован)

add_credit

POST /credits (предполагается, что пользователь аутентифицирован)

Для ошибок вы должны вернуть ошибку в теле в формате, в котором вы получили запрос, поэтому, если вы получите:

DELETE /users/1.xml

Вы отправили бы ответ обратно в XML, то же самое было бы верно для JSON и т.д ...

Для аутентификации вы должны использовать http аутентификацию.

jonnii
источник
1
Я бы не использовал createкак часть URI (помните, что URI должны быть существительными, а методы HTTP должны быть глаголами, которые работают с этими существительными.) Вместо этого у меня был бы такой ресурс, /users/1/activeкоторый может быть простым логическим, и это может быть установите PUTting 1 или 0 для этого ресурса.
Фридо
Вы правы, я достал / создать. Это должна быть просто запись на синглтон-ресурсе.
Джонни
3
Я также не буду использовать activationURI, если вы не будете явно манипулировать ресурсом и управлять им по имени /users/1/activation. Что делает GET на это? Что делает PUT? Мне точно кажется, что вы глаголите URI. Кроме того, что касается согласования типа контента, его также лучше всего не указывать в URI и вставлять в заголовки, например Accept.
Cheeso
6
  1. Используйте сообщение, когда вы не знаете, как будет выглядеть новый URI ресурса (вы создаете нового пользователя, приложение назначит новому пользователю его идентификатор), PUT для обновления или создания ресурсов, которые вы знаете, как они будут представлены (пример : PUT /myfiles/thisismynewfile.txt)
  2. вернуть описание ошибки в теле сообщения
  3. Вы можете использовать HTTP-аутентификацию (если этого достаточно).
Арьян
источник
5

Я хотел бы предложить (в качестве первого прохода), что PUTследует использовать только для обновления существующих объектов. POSTследует использовать для создания новых. т.е.

/api/users     when called with PUT, creates user record

не чувствует себя хорошо для меня. Однако остальная часть вашего первого раздела (использование глагола) выглядит логично.

Брайан Агнью
источник
возможно, кто-то подумал, что это не совсем ответ на его вопрос
lubos hasko
6
Мое взятие PUT по сравнению с POST для создания новых сущностей заключается в использовании PUT, когда вызывающая сторона контролирует имя ресурса, поэтому вы можете PUT для точного ресурса и POST, когда вызываемая сторона контролирует новое имя ресурса (как в примере здесь).
SteveD
5

Подробно, но скопировано из спецификации метода HTTP 1.1 по адресу http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

9,3 ПОЛУЧИТЬ

Метод GET означает получение любой информации (в форме объекта), идентифицируемой посредством Request-URI. Если Request-URI ссылается на процесс создания данных, то именно полученные данные должны быть возвращены в качестве объекта в ответе, а не исходный текст процесса, если только этот текст не является выходом процесса.

Семантика метода GET изменяется на «условное GET», если сообщение запроса включает в себя поле заголовка If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match или If-Range. Условный метод GET запрашивает, чтобы объект передавался только при обстоятельствах, описанных в поле (ах) условного заголовка. Условный метод GET предназначен для уменьшения ненужного использования сети, позволяя обновлять кэшированные объекты без необходимости многократных запросов или передачи данных, уже хранящихся у клиента.

Семантика метода GET изменяется на «частичное GET», если сообщение запроса включает поле заголовка Range. Частичное GET запрашивает, чтобы была передана только часть объекта, как описано в разделе 14.35. Метод частичного GET предназначен для уменьшения ненужного использования сети, позволяя завершить частично извлеченные объекты без передачи данных, уже сохраненных клиентом.

Ответ на GET-запрос кэшируется тогда и только тогда, когда он соответствует требованиям для HTTP-кэширования, описанным в разделе 13.

См. Раздел 15.1.3 для соображений безопасности при использовании для форм.

9,5 ПОСТ

Метод POST используется для запроса, чтобы исходный сервер принял объект, заключенный в запросе, в качестве нового подчиненного ресурса, идентифицируемого Request-URI в строке запроса. POST разработан для того, чтобы унифицированный метод мог выполнять следующие функции:

  - Annotation of existing resources;
  - Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;
  - Providing a block of data, such as the result of submitting a
    form, to a data-handling process;
  - Extending a database through an append operation.

Фактическая функция, выполняемая методом POST, определяется сервером и обычно зависит от Request-URI. Размещаемая сущность подчиняется этому URI так же, как файл подчиняется каталогу, в котором он находится, новостная статья подчиняется группе новостей, в которой она размещена, или запись подчиняется базе данных.

Действие, выполняемое методом POST, может не привести к ресурсу, который может быть идентифицирован с помощью URI. В этом случае либо 200 (ОК), либо 204 (Нет содержимого) является подходящим статусом ответа, в зависимости от того, включает ли ответ объект, который описывает результат.

Если ресурс был создан на исходном сервере, ответ ДОЛЖЕН быть 201 (Создан) и содержать объект, который описывает состояние запроса и ссылается на новый ресурс, и заголовок Location (см. Раздел 14.30).

Ответы на этот метод не могут быть кэшированы, если ответ не включает в себя соответствующие поля заголовка Cache-Control или Expires. Однако ответ 303 (см. «Другое») можно использовать для того, чтобы указать пользовательскому агенту извлечь кэшируемый ресурс.

POST-запросы ДОЛЖНЫ соответствовать требованиям к передаче сообщений, изложенным в разделе 8.2.

См. Раздел 15.1.3 для соображений безопасности.

9,6 ставок

Метод PUT запрашивает, чтобы вложенный объект был сохранен под предоставленным Request-URI. Если Request-URI ссылается на уже существующий ресурс, вложенный объект СЛЕДУЕТ рассматривать как модифицированную версию, находящуюся на исходном сервере. Если Request-URI не указывает на существующий ресурс, и этот URI может быть определен как новый ресурс запрашивающим пользовательским агентом, сервер происхождения может создать ресурс с этим URI. Если новый ресурс создан, сервер происхождения ДОЛЖЕН проинформировать пользовательский агент через ответ 201 (Создано). Если существующий ресурс изменен, то должны быть отправлены коды ответа 200 (ОК) или 204 (Нет содержимого), чтобы указать успешное завершение запроса. Если ресурс не может быть создан или изменен с помощью Request-URI, ДОЛЖЕН быть дан соответствующий ответ об ошибке, отражающий природу проблемы. Получатель объекта НЕ ДОЛЖЕН игнорировать какие-либо заголовки Content- * (например, Content-Range), которые он не понимает или не реализует, и ДОЛЖЕН возвращать ответ 501 (Не реализовано) в таких случаях.

Если запрос проходит через кеш, а Request-URI идентифицирует один или несколько кешируемых в данный момент объектов, эти записи ДОЛЖНЫ рассматриваться как устаревшие. Ответы на этот метод не кешируются.

Принципиальное различие между запросами POST и PUT отражается в различном значении Request-URI. URI в запросе POST идентифицирует ресурс, который будет обрабатывать вложенный объект. Этот ресурс может быть процессом приема данных, шлюзом к другому протоколу или отдельным объектом, принимающим аннотации. Напротив, URI в запросе PUT идентифицирует объект, заключенный в запросе - пользовательский агент знает, для чего предназначен URI, и сервер НЕ ДОЛЖЕН пытаться применить запрос к какому-либо другому ресурсу. Если сервер желает, чтобы запрос был применен к другому URI,

он ДОЛЖЕН отправить ответ 301 (постоянно перемещен); Затем пользовательский агент МОЖЕТ принять собственное решение относительно того, следует ли перенаправить запрос.

Один ресурс МОЖЕТ быть идентифицирован многими различными URI. Например, статья может иметь URI для идентификации «текущей версии», которая отделена от URI, идентифицирующего каждую конкретную версию. В этом случае запрос PUT для общего URI может привести к тому, что исходный сервер определит несколько других URI.

HTTP / 1.1 не определяет, как метод PUT влияет на состояние исходного сервера.

Запросы PUT ДОЛЖНЫ соответствовать требованиям к передаче сообщений, изложенным в разделе 8.2.

Если иное не указано для конкретного заголовка объекта, заголовки объекта в запросе PUT ДОЛЖНЫ применяться к ресурсу, созданному или измененному PUT.

9.7 УДАЛИТЬ

Метод DELETE запрашивает, чтобы исходный сервер удалил ресурс, указанный в Request-URI. Этот метод МОЖЕТ быть отменен вмешательством человека (или другими средствами) на исходном сервере. Клиент не может быть гарантирован, что операция была выполнена, даже если код состояния, возвращенный с исходного сервера, указывает, что действие было успешно выполнено. Однако серверу НЕ СЛЕДУЕТ указывать успех, если только во время ответа он не намерен удалить ресурс или переместить его в недоступное место.

Успешный ответ ДОЛЖЕН быть 200 (ОК), если ответ включает в себя объект, описывающий состояние, 202 (Принят), если действие еще не было выполнено, или 204 (Нет содержимого), если действие было выполнено, но ответ не включает сущность.

Если запрос проходит через кеш, а Request-URI идентифицирует один или несколько кешируемых в данный момент объектов, эти записи ДОЛЖНЫ рассматриваться как устаревшие. Ответы на этот метод не кешируются.

gahooa
источник
2

О кодах возврата REST: неправильно смешивать коды протокола HTTP и результаты REST.

Однако я видел много реализаций, смешивающих их, и многие разработчики могут не согласиться со мной.

Коды возврата HTTP связаны с HTTP Requestсамим собой. Вызов REST выполняется с использованием запроса протокола передачи гипертекста, и он работает на более низком уровне, чем сам вызванный метод REST. REST является концепцией / подходом, и его выходные данные являются бизнес / логическим результатом, в то время как код результата HTTP является транспортным .

Например, возвращение «404 Не найдено» при вызове / users / вызывает путаницу, поскольку это может означать:

  • Неверный URI (HTTP)
  • Пользователи не найдены (REST)

«403 Запрещено / Доступ запрещен» может означать:

  • Требуется специальное разрешение. Браузеры могут справиться с этим, спросив пользователя / пароль. (HTTP),
  • Неправильные разрешения доступа настроены на сервере. (HTTP),
  • Вам необходимо пройти проверку подлинности (REST)

И этот список может продолжаться с «500 Server error» (ошибка в HTTP-запросе Apache / Nginx или ошибка бизнес-ограничения в REST) ​​или другими ошибками HTTP и т. Д.

Из кода трудно понять, что было причиной сбоя, HTTP (транспортный) сбой или REST (логический) сбой.

Если HTTP-запрос физически выполнен успешно, он всегда должен возвращать 200 кодов, независимо от того, найдены записи или нет. Потому что ресурс URI найден и обработан сервером http. Да, он может вернуть пустой набор. Можно ли получить пустую веб-страницу с 200 в результате http, верно?

Вместо этого вы можете вернуть 200 HTTP-код и просто JSON с пустым массивом / объектом или использовать флаг результата / успеха bool для информирования о состоянии выполненной операции.

Кроме того, некоторые интернет-провайдеры могут перехватить ваши запросы и вернуть вам http-код 404. Это не означает, что ваши данные не найдены, но что-то не так на транспортном уровне.

Из вики :

В июле 2004 года британский телекоммуникационный провайдер BT Group развернул систему блокировки контента Cleanfeed, которая возвращает ошибку 404 при любом запросе контента, который, по мнению Internet Watch Foundation, считается потенциально незаконным. Другие Интернет-провайдеры возвращают ошибку HTTP 403 «Запрещено» при тех же обстоятельствах. Практика использования фальшивых ошибок 404 в качестве средства сокрытия цензуры была также отмечена в Таиланде и Тунисе. В Тунисе, где цензура была жестокой до революции 2011 года, люди узнали о природе фальшивых ошибок 404 и создали воображаемого персонажа по имени «Аммар 404», который представляет «невидимого цензора».

Marcodor
источник