ДИЗАЙН REST API - Получение ресурса через REST с разными параметрами, но с тем же шаблоном URL

92

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

У меня есть URL-адреса REST для представления ресурса "пользователей". Я могу ПОЛУЧИТЬ пользователя с идентификатором или адресом электронной почты, но представление URL остается одинаковым для обоих. Просматривая множество блогов и книг, я вижу, что люди делали это разными способами. Например

прочтите эту практику в книге и где-нибудь в stackoverflow (я не могу снова найти ссылку)

GET /users/id={id}
GET /users/email={email}

прочтите эту практику во многих блогах

GET /users/{id}
GET /users/email/{email}

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

GET /users?id={id}
GET /users?email={email}

У меня вопрос: какая из всех этих практик будет наиболее разумной для разработчиков, использующих API, и почему? Я считаю, что в отношении дизайна URL-адресов REST и соглашений об именах нет установленных правил, но я просто хотел знать, какой путь мне следует выбрать, чтобы помочь разработчикам лучше понять API.

Любая помощь приветствуется!

шахши15
источник
1
Я знаю, что это немного устарело, но ища похожие ресурсы, я натыкаюсь на этот вопрос и тот, который вы искали. Я считаю, что это именно этот stackoverflow.com/a/9743414/468327
Джоэл Бергер

Ответы:

104

По моему опыту, GET /users/{id} GET /users/email/{email}это наиболее распространенный подход. Я также ожидаю, что методы вернут 404 Not Found, если пользователь не существует с предоставленным idили email. Я не удивлюсь, увидевGET /users/id/{id} (хотя, на мой взгляд, это избыточно).

Комментарии к другим подходам

  1. GET /users/id={id} GET /users/email={email}
    • Я не думаю, что видел это, и если бы я видел это, это было бы очень запутанным. Это похоже на попытку имитировать параметры запроса с параметрами пути.
  2. GET /users?id={id} GET /users?email={email}
    • Думаю, вы попали в точку, когда упомянули об использовании параметров запроса для фильтрации.
    • Будет ли когда - нибудь смысл назвать этот ресурс с оба апом idи email(например GET /users?id={id}&email={email})? В противном случае я бы не стал использовать такой метод одного ресурса.
    • Я ожидал, что этот метод для получения списка пользователей с необязательными параметрами запроса для фильтрации, но я не ожидал id, emailчто среди параметров будет какой-либо уникальный идентификатор. Например: GET /users?status=BANNEDможет вернуть список заблокированных пользователей.

Посмотрите этот ответ на связанный вопрос.

ДэнниМо
источник
Спасибо за ваш вклад. Собственно ты прав. Похоже, я прочитал №1 в книге «RESTful java с Jax-rs», но несколько вне контекста. Но я очень хорошо помню, как читал это в качестве ответа на один из вопросов о самом stackoverflow (поверьте мне, когда я говорю, что очень стараюсь найти эту ссылку, чтобы доказать своим коллегам :)), и # 2 это именно то, чем я был находясь в поиске. Немного отзывов о дизайне. Спасибо!
shahshi15
PS: Я не уверен, что публикация этого правила здесь, но вы, вероятно, можете пролить свет и на один из моих других вопросов? пожалуйста? :) stackoverflow.com/questions/20508008/…
shahshi15
просто чтобы уточнить ваше заявление о резервировании для /users/id/{id} это обеспечивает расширенную функциональность, просто позволяет получить доступ к одному ресурсу через несколько идентификаторов (id, guid, name). также ответил здесь
Daniel Dubovski
4
Я бы ответил, что подходящим способом ссылки на конкретного пользователя, например, будет / users / {id}. Если вы хотите найти пользователей по определенному адресу электронной почты, который не является уникальным идентификатором для пользователей, я бы сделал / users? Email = {email}, поскольку это способ фильтровать совокупность пользователей, а не определять один конкретный ресурс по его ресурсу. идентификатор как / users / {id}.
Kevin M
Отличный ответ! Большие пальцы за это. Единственное, что я бы порекомендовал сделать, это также немного изменить ваш API, поскольку REST должен быть ориентирован на имя, поэтому ваши сопоставления ресурсов должны быть примерно такими: GET /user/1234а неGET /users/123
Сэмми
38

Если посмотреть на это прагматично, у вас есть группа пользователей:

/users   # this returns many

У каждого пользователя есть выделенное местоположение ресурса:

/users/{id}    # this returns one

У вас также есть несколько способов поиска пользователей:

/users?email={email}
/users?name=*bob*

Поскольку это все параметры запроса к / users, все они должны возвращать списки .. даже если это список из 1.

Я написал здесь сообщение в блоге о прагматичном дизайне RESTful API, в котором говорится об этом, среди прочего, здесь: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

Винай Сахни
источник
Спасибо за ответ vinay. Но если мы подумаем об этом с другой точки зрения, {email}, как и {id}, ВСЕГДА вернет один результат. Если мы действительно ищем, почему бы не использовать? Id = {id} так же, как для электронной почты? Мне было интересно, есть ли способ быть последовательным. PS: новичок в stackoverflow, не знал, что могу дать только один ответ. Но спасибо за ответ! Ценить это. Может быть, вы тоже можете помочь мне с этим: stackoverflow.com/questions/20508008/…
shahshi15
7
Здесь в игру вступает «дизайнерский» аспект дизайна API. У вашего ресурса должно быть выделенное место. Где это место? Местоположение по id? Если так, то вы не «ищите» по идентификатору, вы «получаете» по идентификатору. Но вы ищете по всему остальному. Конечно, здесь нет жестких правил. Это просто перспектива :)
Vinay Sahni
6
Я бы также сказал, что так ваш API будет более стабильным. Вы действительно знаете, что ваш идентификатор уникален, но действительно ли вы уверены в адресе электронной почты? Даже если он уникален, он, вероятно, не постоянный, так как пользователь может его изменить. Итак, / users? Email = {email} дает понять, что это действительно запрос, а не доступ к ресурсу с постоянным идентификатором.
lex82
Я считаю, что это более правильный ответ. Фильтрация коллекции по адресу электронной почты может быть основана на подстановочных знаках, поэтому она не всегда возвращает только один результат.
Kevin M
@VinaySahni Что бы вы сказали о таком шаблоне: /user?by=email&email="abc@pqr.com "/ user? By = id & id =" xashkhx "/ users? FilterA =" a "& filterB =" b "(множественное число для нескольких пользователей)
Shasak
2

О пользовательских ресурсах

на пути /users вы всегда получите набор пользовательских ресурсов.

на пути /users/[user_id]вы можете ожидать, что произойдет несколько вещей:

  1. вы должны получить одноэлементный ресурс, представляющий пользовательский ресурс с его идентификатором [user_id] или
  2. не найдено 404ответ если пользователя с идентификатором [user_id] не существует, или
  3. запрещенный 401, если вам не разрешен доступ к запрошенному пользовательскому ресурсу.

Каждый синглтон уникально идентифицируется своим путем и идентификатором, и вы используете их для поиска ресурса. Для синглтона нельзя использовать несколько путей.

Вы можете запросить путь /usersс параметрами запроса ( GETParameters). Это вернет коллекцию с пользователями, которые соответствуют запрошенным критериям. Возвращаемая коллекция должна содержать пользовательские ресурсы с указанием пути к ресурсам в ответе.

Параметры могут быть любым полем, присутствующим в ресурсах коллекции; firstName, lastName,id

Об электронной почте

Электронная почта может быть ресурсом или свойством / полем ресурса пользователя.

- Электронная почта как собственность пользователя:

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

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: 'john.doe@example.com'
  ...
}

Это означает , что не существует никаких специальных конечных точек для электронной почты, но теперь вы можете найти пользователя по его электронной почте, отправив следующий запрос: /users?email=john.doe@example.com. Что (при условии, что электронные письма уникальны для пользователей) вернет коллекцию с одним пользовательским элементом, который соответствует электронной почте.

- Электронная почта как ресурс:

Но если электронные письма от пользователей также являются ресурсами. Затем вы можете создать API, который /users/[user_id]/emailsвозвращает набор адресов электронной почты для пользователя с идентификатором user_id. /users/[user_id]/emails/[email_id]возвращает адрес электронной почты пользователя с user_id и ['email_id']. Что вы используете в качестве идентификатора, зависит от вас, но я бы предпочел целое число. Вы можете удалить электронное письмо от пользователя, отправив DELETEзапрос по пути, который идентифицирует электронное письмо, которое вы хотите удалить. Так, например, DELETEon /users/[user_id]/emails/[email_id]удалит электронное письмо с email_id, которое принадлежит пользователю с user_id. Скорее всего, только этому пользователю разрешено выполнять эту операцию удаления. Остальные пользователи получат ответ 401.

Если у пользователя может быть только один адрес электронной почты, вы можете придерживаться его. /users/[user_id]/email Это возвращает одноэлементный ресурс. Пользователь может обновить свой адрес электронной почты, PUTуказав адрес электронной почты на этом URL.

Уилт
источник