REST -- развести похожие api.
От: Sharov Россия  
Дата: 19.07.24 12:12
Оценка:
Здравствуйте.

Вот есть api ,например,
/customers/{guid}/passport

Теперь допустим, что решили добавить запрос по уникальному имени
/customers/{name}/passport


Как их можно развести, учитывая что, например, asp .net core не может их различить?
Как лучше добавить поиск по имени в этом случае, чтобы было по rest?
Типа
/customers/name/{name}/passport


или это неправильно с тз идеологии rest?

Заранее благодарю.
Кодом людям нужно помогать!
Отредактировано 19.07.2024 12:13 Sharov . Предыдущая версия .
Re: REST -- развести похожие api.
От: Pzz Россия https://github.com/alexpevzner
Дата: 19.07.24 12:36
Оценка: +1
Здравствуйте, Sharov, Вы писали:

S>Как их можно развести, учитывая что, например, asp .net core не может их различить?


А как он должен их различать?

И {guid} строка и {name} строка. А что имя не похоже на guid, то сейчас как только детей не называют. А ведь когда-нибудь они вырастут и станут пользователями вашей программы...
Re: REST -- развести похожие api.
От: gyraboo  
Дата: 19.07.24 12:40
Оценка:
Здравствуйте, Sharov, Вы писали:

S>или это неправильно с тз идеологии rest?


Мне нравится Filter API, реализованное в движке JHipster:
https://cirovladimir.wordpress.com/2019/06/26/jhipster-about-filtering-entities/
Т.е. автоматически можно собирать любую поисковую конструкцию с полями сущности, в твоём случае будет выглядеть так:
Полное совпадение:
customer/passport?name.equals=ИМЯ
Вхождение подстроки:
customer/passport?name.contains=ИМЯ

Идеологически /customers/{name}/passport некорректно, потому что динамической частью урла в православном РЕСТе может быть первичный только идентификатор, это guid, а не name. Уникальность name не делает это поле идентификатором.
Re[2]: REST -- развести похожие api.
От: Sharov Россия  
Дата: 19.07.24 12:44
Оценка:
Здравствуйте, Pzz, Вы писали:


Pzz>А как он должен их различать?


В том то и дело, что никак. Но как-то надо эти запросы развести.
Добавить prefix name -- /customers/name/{name}/passport

Pzz>И {guid} строка и {name} строка. А что имя не похоже на guid, то сейчас как только детей не называют. А ведь когда-нибудь они вырастут и станут пользователями вашей программы...


Эти вымышленный случай не из предметной области, это просто пример. В предметной области есть сущности, которых
запрашивали по id, решили добавить\переделать под имена сущностей, который уникальны. И вот как-то теперь это надо разруливать.
Кодом людям нужно помогать!
Re: REST -- развести похожие api.
От: kov_serg Россия  
Дата: 19.07.24 12:47
Оценка: 16 (2) +1 -1
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте.

...
S>Как их можно развести, учитывая что, например, asp .net core не может их различить?
/api/v2/customers/{name}/passport
Re: REST -- развести похожие api.
От: RushDevion Россия  
Дата: 19.07.24 16:08
Оценка: 85 (3) +1
Проще всего, наверное, как нибудь так (раз уж имя и guid — равнозначные уникальные идентификаторы пользователя):
// /customers/{nameOrGuid}/passport
PassportDto GetPassport(string nameOrGuid) { 
   if (Guid.TryParse(nameOrGuid, out var uid) {
      return _usersRepo.FindPassportByUid(uid)?.ToDto();
   }
   return _usersRepo.FindPassportByName(nameOrGuid)?.ToDto();
}
Re: REST -- развести похожие api.
От: DiPaolo Россия  
Дата: 19.07.24 16:23
Оценка: 5 (1) +2
Сразу помним, что нет никакого "правильного" РЕСТа. Каждый вправе делать как хочет.

А логичные варианты тут, на мой взгляд, следующие (на основе принципов ресурсов и операций над ними):

1. красивый и лаконичный
/passports/find?name={name}


2. менее красивый, более длинный, но все еще логичный
/customers/find/by-name/{name}/passport


3. ну либо две последовательные операции:
customer = /customers/find?name={name}

/customers/{customer.id}/passport
Патриот здравого смысла
Re: REST -- развести похожие api.
От: scf  
Дата: 19.07.24 16:57
Оценка: 5 (1)
Здравствуйте, Sharov, Вы писали:

S>
S>/customers/name/{name}/passport
S>


Я бы так и сделал. REST нужен, чтобы любой человек, который слышал про REST, понимал, как пользоваться твоим апи. Поэтому на первом месте должен быть здравый смысл и умение делать для людей.
Re: REST -- развести похожие api.
От: Qulac Россия  
Дата: 19.07.24 18:24
Оценка: -1
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте.


S>Вот есть api ,например,

S>
S>/customers/{guid}/passport
S>

S>Теперь допустим, что решили добавить запрос по уникальному имени
S>
S>/customers/{name}/passport
S>


S>Как их можно развести, учитывая что, например, asp .net core не может их различить?

S>Как лучше добавить поиск по имени в этом случае, чтобы было по rest?
S>Типа
S>
S>/customers/name/{name}/passport
S>


S>или это неправильно с тз идеологии rest?


S>Заранее благодарю.


У меня только один совет по rest api: "Не используйте rest api" Толку от следования этому "стандарту", ровным счетом ноль.
Программа – это мысли спрессованные в код
Re: REST -- развести похожие api.
От: · Великобритания  
Дата: 19.07.24 21:30
Оценка: 5 (1)
Здравствуйте, Sharov, Вы писали:

S>Как их можно развести, учитывая что, например, asp .net core не может их различить?

S>Как лучше добавить поиск по имени в этом случае, чтобы было по rest?
/passports?customer.name={name}
/passports?customer.guid={guid}
Не так разве?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: REST -- развести похожие api.
От: Sharov Россия  
Дата: 19.07.24 23:21
Оценка:
Здравствуйте, RushDevion, Вы писали:

RD>Проще всего, наверное, как нибудь так (раз уж имя и guid — равнозначные уникальные идентификаторы пользователя):

RD>
RD>// /customers/{nameOrGuid}/passport
RD>PassportDto GetPassport(string nameOrGuid) { 
RD>   if (Guid.TryParse(nameOrGuid, out var uid) {
RD>      return _usersRepo.FindPassportByUid(uid)?.ToDto();
RD>   }
RD>   return _usersRepo.FindPassportByName(nameOrGuid)?.ToDto();
RD>}
RD>


Тоже так хотел, но в итоге остановился на /passport?name=""
Кодом людям нужно помогать!
Re[2]: REST -- развести похожие api.
От: Sharov Россия  
Дата: 19.07.24 23:22
Оценка: 1 (1) +1
Здравствуйте, DiPaolo, Вы писали:

DP>Сразу помним, что нет никакого "правильного" РЕСТа. Каждый вправе делать как хочет.


DP>А логичные варианты тут, на мой взгляд, следующие (на основе принципов ресурсов и операций над ними):


DP>1. красивый и лаконичный

DP>
DP>/passports/find?name={name}
DP>


Ага, так и сделал, только без find.
Кодом людям нужно помогать!
Re: REST -- развести похожие api.
От: vsb Казахстан  
Дата: 19.07.24 23:44
Оценка:
В контролере разводи как считаешь нужным. Вопрос не понятен. Пиши контролер на /customers/{id}/passport и в контролере уже разбирайся, что там в id — guid или не guid. В первом случае один запрос, во втором — другой.
Re[3]: REST -- развести похожие api.
От: DiPaolo Россия  
Дата: 20.07.24 16:24
Оценка:
S>Ага, так и сделал, только без find.

Точно! Так даже лучше
Патриот здравого смысла
Re: REST -- развести похожие api.
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.07.24 10:57
Оценка: 10 (1)
Здравствуйте, Sharov, Вы писали:

S>Как их можно развести, учитывая что, например, asp .net core не может их различить?

Как уже написали, единого "правильного" рецепта нет.
У одного и того же ресурса может быть несколько альтернативных путей — это нормально.
Мне не очень нравится идея перенести поиск в параметры:
customers/passport?name=a
customers/passport?guid=aaffbc1-...


Но это — интуитивно, на основе догадок.
Основная — такая: а нет ли у нас случайно ресурса /customers/{guid}/, который возвращает "полного" кастомера? С тем, что customers/{guid}/passport — это уточнение, возвращающее суб-ресурс?

В таком случае "выворачивание кастомера наизнанку" затрудняет восприятие такого API.
Нет, формально-то можно-то поисковые параметры к чему угодно приписать. И вместо /customers/a/ писать /customers?name=a, а вместо /customers/a/passport/issuer писать customers/passport/issuer?name=a.
Но это требует выворачивания мозга. В том числе и (вторая догадка) потому, что у нас, наверное, параметры-то подразумеваются необязательными.
То есть в исходном API мы могли написать /customers/, и это бы дало всех кастомеров; и только если мы хотим ограничиться конкретным кастомером, мы полезем вглубь, в /customers/a/.
А тут что мы получим, если уберём query part из customers/passport/issuer?name=a? customers/passport/issuer/ нам явно выдаст 400, а не список всех УВД РФ.
Так что мне ближе всего решение с https://rsdn.org/forum/design/8783785.1
Автор: RushDevion
Дата: 19.07 19:08
.
Оно встречается в проде — в частности, в Microsoft Graph повсеместно гуиды взаимозаменяемы с UPN или FQDN. Плюс ещё и c псевдонимами типа "me" или "myorganization".
Преимущество его — удобство в использовании.
Грубо говоря, вы пишете какой-нибудь утилитный метод вроде RetrieveOrganizationUsers(...).
Можно ему в аргументы отдать (organizationId: Guid), и гвоздями забить в него схему роутинга:
var orgUri = SERVICE_BASE_URI + "/customers/"+organizationId + "/";
var userListUri = orgUri + "/users/";

Тогда при смене этой схемы придётся перепахивать все-все такие функции:
var orgUri = SERVICE_BASE_URI + "/customers/?id="+organizationId + "/";
var userListUri = orgUri + "/users/";

А можно сразу принимать в аргументах orgUri, и полагаться на соглашение о том, что users всегда лежат под ней:
string getOrgUsersUri(string orgUri) => Path.join(orgUri, "users");

И тогда
Request<User> RetrieveOrganizationUsers(string orgUri) 
{
   var userListUri = getOrgUsersUri(orgUri); 
   // алга!
}

Теперь добавление в клиента умения искать организацию по имени сводится к добавлению к функции getOrgUri(Guid id) перегрузки getOrgUri(string name), а всё остальное можно вовсе не трогать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: REST -- развести похожие api.
От: Sharov Россия  
Дата: 25.07.24 16:19
Оценка: +1
Здравствуйте, DiPaolo, Вы писали:

S>>Ага, так и сделал, только без find.

DP>Точно! Так даже лучше

Дело не в лучше. Тут пишут:

3. Do not Use Verbs in the URI
It is not correct to put the verbs in REST URIs. REST uses nouns to represent resources, and HTTP methods (GET, POST, PUT, DELETE, etc.) are then used to perform actions on those resources, effectively acting as verbs.

If we use verbs in the URI, we are most probably creating an RPC-style method call having a JSON or XML request/response format. It would be incorrect to call it REST.

/device-management/managed-devices/{id}/scripts/{id}/execute //It is RPC, and not REST
In cases, where we need to perform some action that does not apply naturally to the definition of resources, we can create the custom URIs that can be considered nouns/resources and perform an action over them.

For example, instead of invoking /scripts/{id}/execute , we can create a resource for all scripts currently executing and submit a script to it if we want to execute a script.


Т.е. без find банально правильнее.
Кодом людям нужно помогать!
Re[2]: REST -- развести похожие api.
От: Sharov Россия  
Дата: 25.07.24 22:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Так что мне ближе всего решение с https://rsdn.org/forum/design/8783785.1
Автор: RushDevion
Дата: 19.07 19:08
.


Это первое, что мне пришло на ум и тоже понравился этот вариант. Но тимлид завернул, а спорить с ним уже надоело.
Захотелось нервы поберечь, поэтому выбрал /passport?query, который всех устроил.
Кодом людям нужно помогать!
Re[3]: REST -- развести похожие api.
От: Qulac Россия  
Дата: 26.07.24 03:35
Оценка: +1 :)
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:


S>>Так что мне ближе всего решение с https://rsdn.org/forum/design/8783785.1
Автор: RushDevion
Дата: 19.07 19:08
.


S>Это первое, что мне пришло на ум и тоже понравился этот вариант. Но тимлид завернул, а спорить с ним уже надоело.

S>Захотелось нервы поберечь, поэтому выбрал /passport?query, который всех устроил.

Вот этим rest api и плох — появляется повод для споров на пустом месте.
Программа – это мысли спрессованные в код
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.