Форум программистов, компьютерный форум, киберфорум
REST API
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768

RESTful: зачем?

06.02.2020, 00:25. Показов 1450. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вопрос не столько по .NET Core (хотя реализации на нём), сколько общего характера.

Какой практический смысл строго соблюдать базовые принипы RESTful? Вот те самые, что URL - это ресурс (в т.ч. многоуровневый), а HTTP-методы - действия над ресурсами. И ещё, что все методы одного ресурса оперируют исключительно однотипными объектами, т.е. если GET/id возвращает 'SomeDto', то PUT и POST должны принимать на вход его и только его.

И почему некоторые фронтэндеры (да и бэкэндеры из других языков) так рьяно пытаются это продвигать? Вживую пытался спрашивать, но так суть и не уловил.

Там что ли на стороне фронтэнд-фреймворков возникают какие-то непроходимые сложности при работе за пределами этой идеологии?

Просто с точки зрения десктоп-бэкэндера как ни пытаюсь, не могу впихнуть логику даже мало-мальски сложного бизнес-объекта в эти рамки. Т.е. если это простой справочник, то да, всё красиво, но как только появляется какая-нибудь сложная сущность типа "счёт", то она сразу же обрастает толпой кастомных специфичных действий, которые либо вообще сущность не меняют и не возвращают, либо затрагивают отдельные её части, либо требуют на вход/выход специфичные DTO, которые в хранилище не мапятся.

Но при этом с точки зрения REST нельзя использовать [POST] /api/1.4/invoices/42/recalcStatus/, ибо это уже не REST, т.к. глагол в урле.

Да и даже на примере справочника возникают казусы:
[GET] /api/1.6/towns/42 => 'TownDto'.
[GET] /api/1.6/towns => 'IEnumerable<TownDto>'.

И если вдруг сущность слишком жирная и в некоторых сценариях требуется вернуть коллекцию 'TownShortDto', то вот так уже нельзя:
[GET] /api/1.6/towns => 'IEnumerable<TownShortDto>'.
Т.к. данный URL уже занят.
Говорят, можно использовать такой вот преподвыверт:
[GET] /api/1.6/shortTowns => 'IEnumerable<TownShortDto>'.
Но выглядит это запутанно - ведь с точки зрения БЛ это, по сути, один тот же объект предметной области, просто немного в разной комплектации. Да и это вырожденный ресурс получается, т.к., скорее всего, на нём не получится реализовать методы добавления/обновления, т.к. 'TownShortDto' попросту не содержит всех нужных данных.

И так тоже нельзя:
[GET] /api/1.6/towns/?shotMode=true => 'IEnumerable<TownShortDto>'.
Т.к. параметры запроса к URL не относятся.

И так тоже не канон:
[GET] /api/1.6/towns/shortMode => 'IEnumerable<TownShortDto>'.[/INLINE]
Т.к. URL - это ресурс, а 'shortMode' под это понятие не особо подпадает с точки зрения REST.

P.S.: в общем, если кому несложно, поделитесь личным опытом, зачем, почему и актуально ли вообще следовать этому на проектах со сложной бизнес-логикой?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
06.02.2020, 00:25
Ответы с готовыми решениями:

Spring Restful
Здравствуйте,только недавно начал вникать в web-программирование. Я пишу веб сервис с помощью Spring и у меня возникли вопросы: 1) Каким...

RESTful WebService
Всем привет! Я написал простой веб-сервис. Локально все работает хорошо, но когда задеплоил на сервер, сервер возвращает 404. В...

RESTful и поисковые системы
Приветствую друзья. У меня вопрос по поводу web приложения работающих по технологии RESTful, а именно я буду говорить про web сайт. ...

12
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
06.02.2020, 01:42
Цитата Сообщение от kotelok Посмотреть сообщение
Но при этом с точки зрения REST нельзя использовать [POST] /api/1.4/invoices/42/recalcStatus/, ибо это уже не REST, т.к. глагол в урле.
Работал на двух больших проектах с REST архитектурой API. В обоих использовались подобные кастомные действия.
Вопрос очень популярный в интернетах. Чтобы не нарушать каноны предлагаются достаточно дикие решения CRUD действиями доводить обьект до нужного состояния, например в данном случае установить поле Invoice.Status = RecalcStatusRequested, а сервис должен триггерить нужные действия при таком апдэйте.

Цитата Сообщение от kotelok Посмотреть сообщение
[GET] /api/1.6/towns/?shotMode=true => 'IEnumerable<TownShortDto>'.
Мне норм выглядит. Канонический url ресурса с дополнительным параметром запроса.

Цитата Сообщение от kotelok Посмотреть сообщение
Какой практический смысл строго соблюдать базовые принипы RESTful?
Какой практический смысл стандартов? Чтобы все было единообразно.
Не вижу ничего плохого в расширении RESTful правилами нужными для проекта, главное знать меру, чтоб API не превратились в зоопарк.

В случае столкновения с подобного рода RESTful эвангелистами советую в качестве аргументов предоставлять API больших и известных сервисов, например Google Cloud Platform.
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
06.02.2020, 07:57  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Мне норм выглядит
Выглядит-то норм, но только вот стандартные .NET-библиотеки такого не понимают, т.е. такой вот код хоть и компилируем с точки зрения C#:
C#
1
2
3
4
5
    [HttpGet]
    public IEnumerable<TownDto> Get()
 
    [HttpGet]
    public IEnumerable<TownShortDto> Get([FromQuery] bool shortMode)
Но в рантайме:
1. Роутер не может разрешить маршрут, т.к. на одном и том же урле два метода с разной сигнатурой и возвращаемыми параметрами.
2. Сваггер падает по той же причине.

Т.е. либо оставаться в рамках REST через вырожденные ресурсы типа /api/shortTowns, и не забывать "связывать" их с базовым ресурсом чисто на уровне документации (чтобы потребитель API осознваал, что ID в обоих ресурсах это одно и то же с точки зрения БЛ, чтобы потребитель не озадачивался, почему это в 'shortTowns' нет добавления/обновления).

Либо отходить от канона и делать [GET] /api/towns/onlyNames, а в документации оговаривать, что все ресурсы исключительно одноуровневые, что первый уровень - всегда ресурс, второй и далее уровень - ID сущностей, вариации возвращемых значений и кастомные действия (в зависимости от контекста или HTTP-метода), прочие параметры - стандартно через параметры запроса после вопросика.
0
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971
06.02.2020, 09:01
я так не заморачивался, мне казалось гораздо важней чтоб юзеру(фронту) было удобно, при этом своя кухня работала быстро и эффективно
если нужен Short делал просто Short и всё, как удобно в конкретном случае(чаще /api/1.6/towns). Правило YAGNI никто не отменял кстати, бесполезных методов апи должно быть как можно меньше
фронтовикам строго до лампочки эти рестфулы - главное чтоб данные адекватные и понятные были.
никто же не дергает апи просто ради веселья вечером - нужно отобразить в гриде дергают данные, данных хватило - отлично, все счастливы. а рестфул там или нет..
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
06.02.2020, 09:18  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
например в данном случае установить поле Invoice.Status = RecalcStatusRequested
Но даже это не всегда спасёт. Т.е. вот именно в этом случае подобный костыль выглядит даже слегка логично, просто вместо значения поля передаётся желаемый алгоритм вычисления его на сервере.

Но может быть и что-нибудь куда более комплексное, например, действие [POST]/api/invoices/42/sendToExternalStorage. Которое проверит условия, выполнит отправку согласно параметрам счёта, обновит статусные поля, вернёт "ок" (или сущность целиком, или специфичный DTO). И вот в таком виде оно вполне логично и понятно выглядит - сущность "счёт", ID=42, действие - отправить. И вот это уже внутрь CRUD заворачивать совсем трэшово получается.

Можно, конечно, снова использовать преподвыверт с фэйковым ресурсом: [POST]/api/externalInvoices (и в теле передавать ID счёта). Но это ведь ещё менее очевидное решение получается, т.к. выглядит оно как простой POST-запрос, т.е. запрос на создание ресурса 'externalInvoice', а по факту:
0. Валидирует сущность из коллекции 'invoices'.
1. Выполняет отправку другого ресурса (invoices) на внешний сервис.
2. Модифицирует другой (invoices) ресурс.
3. Возвращет ID, который нам не особо нужен.
4. А клиент потом ещё вынужден делать дополнительный запрос к ресурсу 'invoices', чтобы получить актуальное состояние сущности. Ну или в п.3, внезапно, в ответ прилетает экземпляр из коллекции 'invoices'.
0
163 / 138 / 35
Регистрация: 25.11.2015
Сообщений: 910
06.02.2020, 10:21
Цитата Сообщение от kotelok Посмотреть сообщение
Но может быть и что-нибудь куда более комплексное, например, действие [POST]/api/invoices/42/sendToExternalStorage. Которое проверит условия, выполнит отправку согласно параметрам счёта, обновит статусные поля, вернёт "ок" (или сущность целиком, или специфичный DTO). И вот в таком виде оно вполне логично и понятно выглядит - сущность "счёт", ID=42, действие - отправить. И вот это уже внутрь CRUD заворачивать совсем трэшово получается.

Для целей апдейта сущностей есть методы PUT и PATCH
POST используется для создания сущности.

т.е. [POST]/api/invoices - создаем сущность. модель для создания должна лежать в теле.

[PUT]/api/invoices/42 - обновляем сущность с id=42. Модель для обновления в теле

[PATCH]/api/invoices/42 - а это для мелочевки, если надо обновить не всю сущность, а некоторые свойства. Список свойств с данными можно положить в тело, а можно и в параметры запроса.

Цитата Сообщение от kotelok Посмотреть сообщение
И почему некоторые фронтэндеры (да и бэкэндеры из других языков) так рьяно пытаются это продвигать? Вживую пытался спрашивать, но так суть и не уловил.
потому что достаточная удобная штука для работы со структуированными данными. Тут главное правильно развернуть роуты, тогда станет намного понятнее. Пример:

GET api/{entity}/{id} - получаем модель сущности
POST api/{entity} - создаем сущность
PUT api/{entity}/{id} - обновляем сущность
DELETE api/{entity}/{id} - соотв удаляем

Если в модели сущности имеются списочные данные, а они в 90% случаем есть, то тогда роуты выстраиваем по принципу от главной к зависимой:

GET api/{entity}/{id}/{subentity}/{subid} - получаем модель сущности
POST api/{entity}/{id}/{subentity} - создаем сущность
PUT api/{entity}/{id}/{subentity}/{subid} - обновляем сущность
DELETE api/{entity}/{id}/{subentity}/{subid} - соотв удаляем

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

Главный принцип - не держать состояние модели. В этом отличие REST от RESTfull. Еще во времена SOAP при работе с сущностью удерживалась сессия и можно было не передавать в разных запросах ид, логины и т.д. С SOAP 10 лет назад много кто работал, даже сейчас сервисы писаные 10 лет назад на нем работают и не сказал бы что это удобно. Пример: turbosms - украинский смс провайдер. Но SOAP канул и сгинул и программисты придумали REST. Сейчас пользуются им. Что будет через 10 лет - еще что-нить придумают.


Цитата Сообщение от nicolas2008 Посмотреть сообщение
В случае столкновения с подобного рода RESTful эвангелистами советую в качестве аргументов предоставлять API больших и известных сервисов, например Google Cloud Platform.
Берем гугловское апи в разделе Calendar API, которое работает по RESTfull
Тынц....

Добавлено через 10 минут
Цитата Сообщение от m0nax Посмотреть сообщение
я так не заморачивался, мне казалось гораздо важней чтоб юзеру(фронту) было удобно, при этом своя кухня работала быстро и эффективно
Я думаю, что эту фигню начали повсеместно внедрять, потому что апи большой и над ним может работать несколько команд и тогда ставится вопрос однотипности. В тот же сваггер REST проще скидывать, если он подчинен общим правилам. Ну это ятд
1
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
06.02.2020, 10:25
kotelok, shortMode это параметр одного метода, не надо создавать два.

Берем гугловское апи в разделе Calendar API, которое работает по RESTfull
yurickas, и? какок вывод?
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
06.02.2020, 10:56  [ТС]
yurickas
Ну так а обозначеныне главные две проблемы как решать-то )?

1. Когда для сущности требуется вернуть с сервера не сущность целиком, а только пару полей в виде соответствующего 'SimpleDto'. И, возможно, ещё какуой-нибудь DTO под конкретный кусочек фронтэнда, чтобы не тянуть пол-базы каждый раз. И, желательно, не создавая для этого фэйк-сущность.

2. Когда сущность не надо обновлять/добавлять/удалять, но для неё нужно выполнить какой-то custom-action, специфичный для предметной области.

Добавлено через 7 минут
Например, вполне типичная задача, когда есть некий справочник:
C#
1
2
3
4
5
6
public class SomeRefItemDto
{
    public int ItemId { get; set; }
    public string Name { get; set; }
    public string HugeDescription { get; set; }
}
И для него надо на форме показать комбобокс на базе свойства 'Name' (не вытягивая на клиент не нужный пока 'HugeDescription'). А если пользователь кликнул в запись, то по 'ItemId' сделать запрос уже полной версии и показать пользователю 'HugeDescritpion'. При этом, метод запроса всего справочника со всеми полями так же может быть востребован в каких-то сценариях, т.е. он тоже должен остаться в API.

Добавлено через 16 минут
Цитата Сообщение от nicolas2008 Посмотреть сообщение
shortMode это параметр одного метода, не надо создавать два.
Тогда этот метод не сможет вернуть типизированный DTO, т.к. в одном случае там будет 'SomeDto', в другом 'SomeSimpleDto', в третьем 'SomeOtherDto', с разным составом полей. И методу придётся возвращать 'object', и в сваггере тогда будет беда с документацией.
0
163 / 138 / 35
Регистрация: 25.11.2015
Сообщений: 910
06.02.2020, 11:07
Цитата Сообщение от kotelok Посмотреть сообщение
И для него надо на форме показать комбобокс на базе свойства 'Name' (не вытягивая на клиент не нужный пока 'HugeDescription'). А если пользователь кликнул в запись, то по 'ItemId' сделать запрос уже полной версии и показать пользователю 'HugeDescritpion'. При этом, метод запроса всего справочника со всеми полями так же может быть востребован в каких-то сценариях, т.е. он тоже должен остаться в API.

Ну, есть паттерн mvvm. На стороне сервера работаем с сущностями, отдаем их вьюмодели, принимаем вьюмодели и по ним работаем с сущностями. Перевод из одного в другое проводится или ручками, или сторонними библиотеками типа Automapper. Отдавать можно и json, а можно и xml. Кому как угодно

Цитата Сообщение от nicolas2008 Посмотреть сообщение
yurickas, и? какок вывод?
Ну, контекст вопроса был в том, что для того чтобы заткнуть рот "евангелистам"© от REST - надо ткнуть их носом в гугловский апи, который не REST. Я ткнул в обратное....

Добавлено через 5 минут
Цитата Сообщение от kotelok Посмотреть сообщение
Тогда этот метод не сможет вернуть типизированный DTO, т.к. в одном случае там будет 'SomeDto', в другом 'SomeSimpleDto', в третьем 'SomeOtherDto', с разным составом полей. И методу придётся возвращать 'object', и в сваггере тогда будет беда с документацией.
ну так и говорю. Вьюмодели. В вьюмодель можешь засунуть что угодно.

Если сервер отдает json строго по модели БД, то первый краш апи который можно получить - это парсинг циклических ссылок из object в json.
1
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
06.02.2020, 19:02
Цитата Сообщение от kotelok Посмотреть сообщение
А если пользователь кликнул в запись, то по 'ItemId' сделать запрос уже полной версии и показать пользователю 'HugeDescritpion'.
А если пользователь захотел 10 раз кликнуть по кнопке для получения полной версии сущности, то все, запинать сервер до смерти?
Как-то делали сервис для централизованного управления рекламой (BING, Google AdWords), у бинга вроде было две версии API в том числе bulk loading, то есть когда грузим очень много толстых(!) объектов, зато потом не пинаем сервер вообще. С тех пор и взял за основу загружать весь граф объекта, что-то скрывать первоначально, если нужно, а обновлять по кускам.

Цитата Сообщение от kotelok Посмотреть сообщение
Например, вполне типичная задача, когда есть некий справочник:
Ну и тут я бы сделал также.
1
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
07.02.2020, 09:37
Цитата Сообщение от yurickas Посмотреть сообщение
Ну, контекст вопроса был в том, что для того чтобы заткнуть рот "евангелистам"© от REST - надо ткнуть их носом в гугловский апи, который не REST. Я ткнул в обратное....
Хотите сказать что у гугла все API соответствуют правилам REST?
Гляньте это
https://cloud.google.com/kuber... ence/rest/
0
163 / 138 / 35
Регистрация: 25.11.2015
Сообщений: 910
07.02.2020, 10:29
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Хотите сказать что у гугла все API соответствуют правилам REST?
Нет. Не хочу. И даже никогда этого не утверждал, а вот некоторые звездоболы утверждают. Тот же апи по календарям есть и в формате SOAP. Реализован для совместимости с CalDav.

Добавлено через 2 минуты
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Гляньте это
Глянул. Особенно понравился вот этот абзац, сорри за гугл-переводчик, но я думаю у Вам с английским лучше сами прочитали в первоисточнике.

Discovery Document - это машиночитаемая спецификация для описания и использования REST API. Он используется для создания клиентских библиотек, плагинов IDE и других инструментов, которые взаимодействуют с API Google. Одна служба может предоставлять несколько документов обнаружения. Эта служба предоставляет следующие документы обнаружения:
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
07.02.2020, 20:47
Цитата Сообщение от yurickas Посмотреть сообщение
Нет. Не хочу. И даже никогда этого не утверждал, а вот некоторые звездоболы утверждают.
К чему тогда комментарий о Calendar API?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.02.2020, 20:47
Помогаю со студенческими работами здесь

RESTful вебсервис: авторизация
Хочу прикрутить небольшую авторизацию к своему веб сервису, подскажите куда копать. Что мне нужно: возможность разделять пользователей...

Пример реального restful сервиса
Привет. Хотел бы себе , для портфолио, да и чтоб изучить тонкости REST технологии, написать такой сервис. Но не какой то Hello world, а...

Restful API + requests JSON
Ребят, доброго времени суток. В данное время я начал заниматься разработкой под Android. У меня есть проект, но я столкнулся с...

Получение объектов в restful-приложении
Здравствуйте. Помогите, пожалуйста, решить проблему. Пишу resful приложение. Из главного приложения возвращаю список объектов ...

RESTful API работа с actions
Всем привет, такой стоит вопрос, у меня есть YII2 и нужно разработать API которая будет отправлять ответ в своём формате. Я не могу...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru