Теперь допустим, что решили добавить запрос по уникальному имени
/customers/{name}/passport
Как их можно развести, учитывая что, например, asp .net core не может их различить?
Как лучше добавить поиск по имени в этом случае, чтобы было по rest?
Типа
Здравствуйте, Sharov, Вы писали:
S>Как их можно развести, учитывая что, например, asp .net core не может их различить?
А как он должен их различать?
И {guid} строка и {name} строка. А что имя не похоже на guid, то сейчас как только детей не называют. А ведь когда-нибудь они вырастут и станут пользователями вашей программы...
Здравствуйте, 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 не делает это поле идентификатором.
В том то и дело, что никак. Но как-то надо эти запросы развести.
Добавить prefix name -- /customers/name/{name}/passport
Pzz>И {guid} строка и {name} строка. А что имя не похоже на guid, то сейчас как только детей не называют. А ведь когда-нибудь они вырастут и станут пользователями вашей программы...
Эти вымышленный случай не из предметной области, это просто пример. В предметной области есть сущности, которых
запрашивали по id, решили добавить\переделать под имена сущностей, который уникальны. И вот как-то теперь это надо разруливать.
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте.
... S>Как их можно развести, учитывая что, например, asp .net core не может их различить?
/api/v2/customers/{name}/passport
Я бы так и сделал. REST нужен, чтобы любой человек, который слышал про REST, понимал, как пользоваться твоим апи. Поэтому на первом месте должен быть здравый смысл и умение делать для людей.
Здравствуйте, 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" Толку от следования этому "стандарту", ровным счетом ноль.
Здравствуйте, Sharov, Вы писали:
S>Как их можно развести, учитывая что, например, asp .net core не может их различить? S>Как лучше добавить поиск по имени в этом случае, чтобы было по rest?
/passports?customer.name={name}
/passports?customer.guid={guid}
Не так разве?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, 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=""
Здравствуйте, DiPaolo, Вы писали:
DP>Сразу помним, что нет никакого "правильного" РЕСТа. Каждый вправе делать как хочет.
DP>А логичные варианты тут, на мой взгляд, следующие (на основе принципов ресурсов и операций над ними):
DP>1. красивый и лаконичный DP>
В контролере разводи как считаешь нужным. Вопрос не понятен. Пиши контролер на /customers/{id}/passport и в контролере уже разбирайся, что там в id — guid или не guid. В первом случае один запрос, во втором — другой.
Здравствуйте, Sharov, Вы писали:
S>Как их можно развести, учитывая что, например, asp .net core не может их различить?
Как уже написали, единого "правильного" рецепта нет.
У одного и того же ресурса может быть несколько альтернативных путей — это нормально.
Мне не очень нравится идея перенести поиск в параметры:
Но это — интуитивно, на основе догадок.
Основная — такая: а нет ли у нас случайно ресурса /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
.
Оно встречается в проде — в частности, в 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 всегда лежат под ней:
Теперь добавление в клиента умения искать организацию по имени сводится к добавлению к функции getOrgUri(Guid id) перегрузки getOrgUri(string name), а всё остальное можно вовсе не трогать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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.
Это первое, что мне пришло на ум и тоже понравился этот вариант. Но тимлид завернул, а спорить с ним уже надоело.
Захотелось нервы поберечь, поэтому выбрал /passport?query, который всех устроил.
.
S>Это первое, что мне пришло на ум и тоже понравился этот вариант. Но тимлид завернул, а спорить с ним уже надоело. S>Захотелось нервы поберечь, поэтому выбрал /passport?query, который всех устроил.
Вот этим rest api и плох — появляется повод для споров на пустом месте.