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

Извлечение из Спецификация языка Java :

Каждое объявление метода в теле интерфейса неявно абстрактно, поэтому его тело всегда представлено точкой с запятой, а не блоком.

Каждое объявление метода в теле интерфейса неявно открыто.

Для совместимости со старыми версиями платформы Java разрешено, но не рекомендуется

blockquote>

Книга должна быть ошибочной или, по крайней мере, сделана путаница.

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

interface Foo {
  void bar();
}

abstract class FooImpl implements Foo {
  /**
   * I want to put documentation here without implementing the method.
   */
  abstract void bar();
}

Но это не влияет на поведение кода.

586
задан SandroMarques 5 August 2016 в 21:05
поделиться

8 ответов

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


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

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


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

  • GET : вывести список членов коллекции с указанием их URI для дальнейшей навигации. Например, перечислите все автомобили на продажу.

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

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

  • УДАЛИТЬ : Значение определяется как «удалить всю коллекцию».


При работе с элементом 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 не имеет состояния: вы создаете сеанс,вы просите сервер предоставить вам ресурсы, используя этот идентификатор сеанса в качестве параметра, и при выходе из системы вы прерываете сеанс или завершаете его.

613
ответ дан 22 November 2019 в 22:02
поделиться

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

activate_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

change_password

PUT /passwords (это предполагает, что пользователем будет authenticated)

add_credit

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

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

DELETE /users/1. xml

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

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

.
11
ответ дан 22 November 2019 в 22:02
поделиться
  1. Use post when you don't know how the new resource URI would look like (you create new user, application would assign the new user it's id), PUT for update or creating resources that you know how они будут представлены (пример: PUT /myfiles/thisismynew file). txt)
  2. верните описание ошибки в теле сообщения
  3. Вы можете использовать HTTP аутентификацию (если этого достаточно) Веб-сервисы должны быть stateles
6
ответ дан 22 November 2019 в 22:02
поделиться

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

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

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

.
5
ответ дан 22 November 2019 в 22:02
поделиться

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

9.3 GET

Метод 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

Метод POST используется для запроса на то, чтобы сервер отправителя принял объект, заключенный в запрос, в качестве нового подчиненного ресурса, идентифицируемого в Request-URI в Request-Line. Метод 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 (OK), либо 204 (No Content) является соответствующим статусом ответа, в зависимости от того, включает ли ответ сущность, описывающую результат.

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

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

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

См. раздел 15.1.3 по вопросам безопасности.

9.6 PUT

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

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

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

он ДОЛЖЕН посылать ответ 301 (Moved Permanently); пользовательский агент MAY затем принимает собственное решение о том, перенаправлять запрос или нет.

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

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

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

Если для конкретного заголовка правоустанавливающего устройства не указано иное, заголовки правоустанавливающих устройств в PUT-запросе ДОЛЖНЫ применяться к ресурсу, созданному или модифицированному PUT.

9.7 Метод DELETE

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

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

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

.
5
ответ дан 22 November 2019 в 22:02
поделиться

re 1 : Пока это выглядит прекрасно. Не забудьте вернуть URI вновь созданного пользователя в заголовке "Location:" в составе ответа на POST вместе с кодом статуса "201 Created".

re 2 : Активация через GET - плохая идея, а включение глагола в URI - это запах конструкции. Вы можете подумать о возвращении формы на GET. В веб-приложении это будет HTML форма с кнопкой submit; в случае использования API, вы можете захотеть вернуть представление, которое содержит URI в PUT для активации учетной записи. Конечно, вы можете включить этот URI и в ответ на POST для /users. Использование PUT гарантирует, что ваш запрос будет idempotent, т.е. он может быть безопасно отправлен снова, если клиент не уверен в успехе. В общем, подумайте о том, в какие ресурсы вы можете превратить свои глаголы (что-то вроде "нумерации глаголов"). Спросите себя, с каким методом ваше конкретное действие наиболее тесно связано. Например, change_password -> PUT; deactivate -> probably DELETE; add_credit -> perhaps POST or PUT. Укажите клиенту соответствующие URI, включив их в свои представительства.

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

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

30
ответ дан 22 November 2019 в 22:02
поделиться

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

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

Цитируя Roy Fielding

REST API должен расходовать почти все его описательная работа по определению тип(ы) носителя, используемого(ых) для представления ресурсное и приводное приложение состояние, или при определении расширенного имена родственников и/или гипертекстовая разметка для существующего стандартные типы СМИ. Любое потраченное усилие описывающий, какие методы использовать для чего URL-адреса, представляющие интерес, должны быть полностью определённый в рамках правила обработки для типа носителя (и, в большинстве случаев, уже определенное по существующим типам СМИ). [Неудача здесь подразумевается, что внеполосный движущее взаимодействие Вместо гипертекста.]

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

Честно говоря, многие видят кучу URI и некоторые GETs и PUTs и POSTs и думают, что REST - это просто. REST - это нелегко. RPC по HTTP - это легко, перемещение блоков данных туда и обратно, проксированных через полезную нагрузку HTTP - это легко. REST, однако, выходит за рамки этого. REST - это агностик протокола. HTTP просто очень популярен и подходит для систем REST.

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

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

Оба подхода, я думаю, имеют свое место, XHTML очень хорошо работает в сценариях, которые перекрывают веб, управляемый человеком и машиной, в то время как первые, более специфические типы данных, как мне кажется, лучше облегчают взаимодействие машины с машиной. Я считаю, что улучшение товарных форматов может сделать переговоры по содержанию потенциально трудными. "app/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"/>

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

77
ответ дан 22 November 2019 в 22:02
поделиться

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

2. , а не пытаться расширить HTTP с большим количеством глаголов, рассмотрите, что ваши предлагаемые глаголы могут быть уменьшены с точки зрения основных HTTP-методов и ресурсов. Например, вместо Activate_Login глагол, вы можете настроить такие ресурсы, как: / API / пользователи / 1 / вход в систему / Active , который является простым логическим. Чтобы активировать логин, просто PUT Документ там, который говорит «True» или 1 или что-то еще. Чтобы деактивировать, поставить документ там пусто или говорит 0 или ложь.

Аналогичным образом, чтобы изменить или установить пароли, просто делайте PUT с / API / пользователей / 1 / пароль .

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

3. Я настоятельно рекомендую к расширению основных кодов состояния HTTP. Если вы не можете найти тот, который точно соответствует вашей ситуации, выберите ближайший и поставьте данные об ошибке в тело ответа. Кроме того, помните, что заголовки HTTP являются расширяемыми; Ваше приложение может определить все пользовательские заголовки, которые вам нравятся. Одно приложение, на которое я работал, например, мог вернуть 404 не найден в нескольких обстоятельствах. Вместо того, чтобы сделать клиента разбирать тело ответа по той причине, мы только что добавили новый заголовок, , расширенный , который содержал наш запатентованный расширение кода состояния. Таким образом, вы можете увидеть ответы, такую ​​как:

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

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

4. Для аутентификации я рекомендую использовать аутентификацию HTTP, если вы можете. Но ИМХО нет ничего плохого в использовании аутентификации на основе cookie, если это легче для вас.

22
ответ дан 22 November 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: