RESTfully оформить / войти или / зарегистрировать ресурсы?

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

GET  /logout   // destroys session and redirects to /
GET  /login    // gets the webpage that has the login form
POST /login    // authenticates credentials against database and either redirects home with a new session or redirects back to /login
GET  /register // gets the webpage that has the registration form
POST /register // records the entered information into database as a new /user/xxx
GET  /user/xxx // gets and renders current user data in a profile view
POST /user/xxx // updates new information about user

У меня такое чувство, что я здесь делаю много не так, после того, как ковырялся в SO и Google.

Начиная с /logout, возможно, поскольку я на самом деле ничего GET не имею - может быть более подходящим POST запрос к /logout, уничтожить сеанс, а затем GET перенаправление. И должен ли остаться /logout срок?

А как насчет /login и /register. Я мог бы изменить /register на /registration, но это не повлияет на фундаментальную работу моей службы - если у нее есть более серьезные проблемы.

Теперь я замечаю, что никогда не раскрываю /user ресурс. Возможно, это можно как-то использовать. Например, возьмем пользователя myUser:

foo.com/user/myUser

or

foo.com/user

Конечному пользователю не требуется эта дополнительная многословность в URI. Однако какой из них визуально более привлекателен?

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

Спасибо!

ОБНОВЛЕНИЕ:

Мне также хотелось бы высказать свое мнение по поводу:

/user/1

vs

/user/myUserName

person Qcom    schedule 21.08.2011    source источник
comment
См. Также: stackoverflow.com/questions/3521290/logout-get-or-post   -  person mwolfetech    schedule 31.08.2011


Ответы (6)


Одна вещь выделяется, в частности, как не REST-ful: использование запроса GET для выхода из системы.

(из http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods)

Некоторые методы (например, HEAD, GET, OPTIONS и TRACE) определены как безопасные, что означает, что они предназначены только для поиска информации и не должны изменять состояние сервера. Другими словами, они не должны иметь побочных эффектов, помимо относительно безобидных эффектов, таких как ведение журнала, кеширование, показ баннерной рекламы или увеличение счетчика веб-сайтов. [...]

[... H] отправка [запросов GET] сервером технически не ограничена никаким образом. Следовательно, неосторожное или преднамеренное программирование может вызвать нетривиальные изменения на сервере. Это не рекомендуется, поскольку это может вызвать проблемы для веб-кеширования, поисковых систем и других автоматизированных агентов [...]

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

http://en.wikipedia.org/wiki/Post/Redirect/Get

http://en.wikipedia.org/wiki/HTTP_303

Отредактируйте, чтобы решить проблемы с дизайном URL:

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

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

Если JRandomUser хочет просмотреть свой профиль, а вы хотите, чтобы URL-адрес был красивее, чем foo.com/user/JRandomUser или foo.com/user/(JRandom's numeric user id here), вы можете создать отдельный URL-адрес только для того, чтобы пользователь мог просматривать свою информацию:

GET foo.com/profile /*examines cookies to figure out who 
                     * is logged in (SomeUser) and then 
                     * displays the same response as a
                     * GET to foo.com/users/SomeUser.
                     */

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

  1. Потребитель: какие ресурсы предназначены для просмотра непосредственно в браузере, для загрузки через XHR или для доступа к другим типам клиентов?
  2. Доступ / идентификация: зависит ли ответ от файлов cookie или источников перехода?
person ellisbben    schedule 30.08.2011
comment
Отличный ответ, спасибо! Если бы я собирался реализовать ваше отдельное предложение URL-адреса (GET foo.com/profile/), было бы это частью, как предлагает momo, уровня представления? Другими словами, что именно должен вернуть этот GET запрос? Веб-страница или какой-нибудь JSON? - person Qcom; 04.09.2011
comment
А, теперь я думаю, что понимаю. Ответ Момо действительно прояснил ситуацию. Таким образом, RESTful API создан, чтобы позволить нескольким платформам использовать ресурсы GET, POST, PUT и DELETE. Веб-сайт - это просто еще одна платформа, имеющая доступ к API. Другими словами, дизайн URL-адреса веб-сайта полностью отличается от дизайна RESTful API. Скажите, пожалуйста, если я все еще ошибаюсь, ха-ха. - person Qcom; 04.09.2011
comment
Да, сделайте свой REST API одним набором URL-адресов, а ваш веб-сайт другим набором. Затем URL-адрес вашего веб-сайта должен возвращать вам соответствующий HTML + Javascript, чтобы страница выполняла соответствующие запросы XmlHttpRequests для ваших URL-адресов API, чтобы действовать как клиент. - person ellisbben; 09.09.2011

RESTful можно использовать в качестве руководства для создания URL-адресов, и вы можете сделать ресурсы сеансов и пользователей:

  • GET /session/new получает веб-страницу с формой входа
  • POST /session аутентифицирует учетные данные по базе данных
  • DELETE /session уничтожает сеанс и перенаправляет на /
  • GET /users/new получает веб-страницу с регистрационной формой
  • POST /users записывает введенную информацию в базу данных как новый / user / xxx
  • GET /users/xxx // получает и отображает текущие данные пользователя в представлении профиля
  • POST /users/xxx // обновляет новую информацию о пользователе

Они могут быть во множественном или единственном числе (я не уверен, какой из них правильный). Я обычно использовал /users для страницы индекса пользователя (как и ожидалось) и /sessions, чтобы увидеть, кто вошел в систему (как и ожидалось).

Использование имени в URL-адресе вместо числа (/users/43 против /users/joe) обычно обусловлено желанием быть более дружелюбным к пользователям или поисковым системам, а не какими-либо техническими требованиями. Либо это нормально, но я рекомендую вам действовать последовательно.

Я думаю, что если вы выберете регистр / вход / выход из системы или sign(in|up|out), это не сработает также с успокаивающей терминологией.

person ndp    schedule 31.08.2011
comment
Потрясающий! Мне нравится, как вы назвали эти ресурсы; это довольно чисто. Хотя, насколько я слышал, не добавляет ли /new в GET /session/ не RESTful? Я слышал, что глаголы обычно оставляют для глаголов HTTP (GET, POST и т. Д.). - person Qcom; 04.09.2011
comment
@Zach new - это не глагол. В данном случае это подресурс сеанса. - person Kugel; 19.04.2013
comment
Как определить, какой сеанс удалить в DELETE / session? Curl не отправляет ни файлы cookie, ни какие-либо параметры в запросе DELETE. Я предполагаю - просто использовать DELETE / session / sessionId? Другой вопрос, как вернуть идентификатор сеанса в POST / session и в каком формате. - person Tvaroh; 03.11.2013
comment
Отдых на самом деле - это способ сделать себя несчастным и тратить время на вещи, которые вообще не имеют значения. - person Jian Chen; 10.12.2015
comment
Лично мне не нравится идея иметь маршруты, возвращающие форму (/ new). Это нарушает разделение между представлением и бизнес-логикой. Та сказал, что без новых маршрутов предложенный выглядит идеально. - person Scadge; 30.05.2017
comment
каков был бы путь отдыха для проверки некоторых данных? Например, как проверка PIN-кода? - person andQlimax; 15.06.2017
comment
Весь этот ответ просто неверен. REST - это получение данных. Итак, в первую очередь GET /session/new следует получать не веб-страницу, а список всех текущих сеансов. Даже не говоря о неправильном добавлении /new. Во-вторых, POST предназначен для создания ресурсов. Я знаю, что этот пост старый, но для людей, читающих его в 2020 году: вам действительно не следует следовать этим рекомендациям. Следуйте другим официальным рекомендациям: https://restfulapi.net/resource-naming/ - person Ophidian; 13.02.2020
comment
Это стиль Rails 9-летней давности о том, как структурировать URL-адреса HTML-страниц. Я согласен, что это не имеет смысла, если вы создаете API, но это не контекст вопроса. В наши дни вы будете рассматривать более запеченные протоколы аутентификации. - person ndp; 14.02.2020
comment
Как бы вы справились со сбросом пароля, используя указанную структуру? users/xxx/password не имеет смысла, потому что вы не знаете идентификатор при сбросе пароля, и sessions/passwords тоже не имеет особого смысла - person Brian Le; 12.06.2020

Сеансы не относятся к RESTful

  • Да, я знаю. Обычно это делается с помощью OAuth, но на самом деле сеансы не являются RESTful. У вас не должно быть ресурса / login / logout в первую очередь потому, что у вас не должно быть сеансов.

  • Если вы собираетесь это сделать, сделайте это RESTful. Ресурсы - это существительные, а / login и / logout - не существительные. Я бы пошел с / session. Это делает создание и удаление более естественным действием.

  • POST vs. GET для сессий - это просто. Если вы отправляете имя пользователя / пароль в виде переменных, я бы использовал POST, потому что я не хочу, чтобы пароль отправлялся как часть URI. Он появится в журналах и, возможно, будет виден по проводам. Вы также рискуете получить сбой программного обеспечения из-за ограничений GET args.

  • Я обычно использую базовую аутентификацию или без аутентификации со службами REST.

Создание пользователей

  • Это один ресурс, поэтому вам не нужно / регистрироваться.

    • POST /user - Creates a user if the requestor cannot specify the id
    • PUT / user / xxx - создайте или обновите пользователя, если заранее знаете идентификатор.
    • GET / user - перечисляет x идентификаторов пользователей
    • GET / user / xxx - ПОЛУЧАЕТ сведения о пользователе с идентификатором xxx
    • DELETE / user / xxx - Удалить пользователя с идентификатором xxx
  • Какой тип ID использовать - сложный вопрос. Вы должны подумать об обеспечении уникальности, о повторном использовании старых идентификаторов, которые были УДАЛЕНЫ. Например, вы не хотите использовать эти идентификаторы в качестве внешних ключей на бэкэнде, если идентификаторы будут переработаны (если это вообще возможно). Вы можете выполнить поиск преобразования внешнего / внутреннего идентификатора, чтобы снизить требования к бэкэнд.

person dietbuddha    schedule 31.08.2011
comment
Это лучший ответ. / login и / logout не являются ресурсами и нарушают идею REST. - person wle8300; 16.09.2016
comment
Аутентификация! = Сессия - person dietbuddha; 13.10.2017
comment
Да, в тезисе Филдинга в разделе 5.1.3 говорится, что состояние [...] сеанса полностью [...] остается за клиентом. Кроме того, я бы сказал, что в идеале аутентификация также должна быть без сохранения состояния на стороне сервера, т.е. вместо того, чтобы хранить активные билеты аутентификации в базе данных, сервер должен иметь возможность проверять учетные данные аутентификации только на основе самих учетных данных, например с помощью автономного криптографического токена в сочетании с закрытым ключом. Итак, вместо ресурса / session можно было бы ввести ресурс / authentication, но это тоже не решает проблему ... - person raner; 03.02.2018
comment
Фактически, / login и / logout - существительные. Я предполагаю, что вы думаете о / log_in и / log_out. - person TiggerToo; 03.09.2018

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

  • Когда мы говорим API, это обычно относится к набору программного интерфейса, а не к уровню представления. REST также ориентирован на данные, а не на презентацию. При этом большинство REST возвращают данные в форме JSON или XML и редко возвращают определенный уровень представления. Эта особенность (возвращение данных, а не прямой веб-страницы) дала возможность REST выполнять многоканальную доставку. Это означает, что один и тот же веб-сервис может отображаться в HTML, iOS, Android или даже использоваться в качестве комбинации сервера с сервером.
  • Очень редко комбинировать HTML и REST в качестве URL-адреса. По умолчанию REST мыслится как службы и не имеют уровня представления. Задача тех, кто использует веб-сервисы, состоит в том, чтобы отображать данные из сервисов, которые они вызывают, в соответствии с тем, что они хотят. В этом случае ваш URL-адрес ниже не соответствует большей части дизайна на основе REST, с которым я сталкивался до сих пор (ни стандартам, таким как те, которые исходят из Facebook или Twitter).
GET  /register // gets the webpage that has the registration form
  • Продолжая с предыдущего пункта, также необычно (и я не встречал), чтобы служба на основе REST выполняла перенаправление, например, предложенные ниже:
GET  /logout   // destroys session and redirects to /
POST /login    // authenticates credentials against database and either redirects home with a new session or redirects back to /login
 

Поскольку REST спроектированы как службы, такие функции, как вход в систему и выход из системы, обычно возвращают результат успеха / неудачи (обычно в формате данных JSON или XML), который затем интерпретирует потребитель. Такая интерпретация может включать перенаправление на соответствующую веб-страницу, как вы упомянули.

  • В REST URL-адрес обозначает предпринимаемые действия. По этой причине мы должны устранить как можно больше двусмысленности. Хотя в вашем случае вполне законно иметь и GET, и POST, которые имеют один и тот же путь (например, / register), которые выполняют разные действия, такой дизайн вносит двусмысленность в предоставляемые услуги и может сбить с толку потребителя ваших услуг. Например, URL-адреса, подобные приведенному ниже, не идеальны для служб на основе REST.
GET  /register // gets the webpage that has the registration form
POST /register // records the entered information into database as a new /user/xxx

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

Что касается реализации вашего REST, это типичная реализация, с которой я столкнулся:

  • GET  /logout  
    

    Выполнить выход из системы и вернуть JSON для обозначения успеха / неудачи операции.

  • POST /login
    

    Отправьте учетные данные на серверную часть. Вернуть успех / неудачу. В случае успеха, как правило, он также возвращает токен сеанса, а также информацию о профиле.

  • POST /register
    

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

  • GET  /user/xxx
    

    Получить профиль пользователя и вернуть формат данных JSON для профиля пользователя

  • POST /user/xxx 
    // renamed to 
    POST /updateUser/xxx
    

    Опубликуйте обновленную информацию профиля в формате JSON и обновите информацию в серверной части. Вернуть звонящему успех / неудачу

person momo    schedule 30.08.2011
comment
Да, если вы интегрируете свой REST API с приложением на основе HTML (через Javascript и AJAX), вы получите огромные преимущества, поскольку JSON изначально анализируется Javascript. В Android / Java JSON проще и проще анализировать по сравнению с XML. - person momo; 31.08.2011
comment
GET / выход из системы опасен. GET должен быть идемпотентным. Также браузеры любят предварительно загружать ‹a› hrefs, что приведет к выходу из системы! - person Kugel; 19.04.2013

Я считаю, что это подход к аутентификации RESTful. Для входа вы используете HttpPut. Этот HTTP-метод можно использовать для создания, если предоставлен ключ и повторные вызовы идемпотентны. Для выхода из системы вы указываете тот же путь в методе HttpDelete. Глаголы не используются. Правильное множественное число коллекций. Методы HTTP поддерживают эту цель.

[HttpPut]
[Route("sessions/current")]
public IActionResult LogIn(LogInModel model) { ... }

[HttpDelete]
[Route("sessions/current")]
public IActionResult LogOff() { ... }

При желании вы можете заменить активным током.

person Chad Kuehn    schedule 21.07.2017

Я бы порекомендовал использовать URL-адрес учетной записи пользователя, аналогичный twitter, где URL-адрес учетной записи пользователя будет примерно таким, как foo.com/myUserName, точно так же, как вы можете перейти в мою учетную запись Twitter с URL-адресом https://twitter.com/joelbyler

Я не согласен с тем, что для выхода из системы требуется POST. В рамках вашего API, если вы собираетесь поддерживать сеанс, то идентификатор сеанса в форме UUID может быть чем-то, что можно использовать для отслеживания пользователя и подтверждения того, что выполняемое действие авторизовано. Тогда даже GET может передать идентификатор сеанса ресурсу.

Короче говоря, я бы порекомендовал вам быть простым, URL-адреса должны быть короткими и запоминающимися.

person joelbyler    schedule 29.08.2011
comment
Вопрос в ресурсах API. Ваш ответ касается уровня представления. - person Henno; 11.10.2019