|
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
|
|
| 06.02.2020, 00:25 | |
|
Ответы с готовыми решениями:
12
Spring Restful RESTful WebService RESTful и поисковые системы |
|
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
|
||||
| 06.02.2020, 01:42 | ||||
|
Вопрос очень популярный в интернетах. Чтобы не нарушать каноны предлагаются достаточно дикие решения CRUD действиями доводить обьект до нужного состояния, например в данном случае установить поле Invoice.Status = RecalcStatusRequested, а сервис должен триггерить нужные действия при таком апдэйте. Не вижу ничего плохого в расширении RESTful правилами нужными для проекта, главное знать меру, чтоб API не превратились в зоопарк. В случае столкновения с подобного рода RESTful эвангелистами советую в качестве аргументов предоставлять API больших и известных сервисов, например Google Cloud Platform.
1
|
||||
|
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
|
|||||||
| 06.02.2020, 07:57 [ТС] | |||||||
1. Роутер не может разрешить маршрут, т.к. на одном и том же урле два метода с разной сигнатурой и возвращаемыми параметрами. 2. Сваггер падает по той же причине. Т.е. либо оставаться в рамках REST через вырожденные ресурсы типа /api/shortTowns, и не забывать "связывать" их с базовым ресурсом чисто на уровне документации (чтобы потребитель API осознваал, что ID в обоих ресурсах это одно и то же с точки зрения БЛ, чтобы потребитель не озадачивался, почему это в 'shortTowns' нет добавления/обновления).Либо отходить от канона и делать [GET] /api/towns/onlyNames, а в документации оговаривать, что все ресурсы исключительно одноуровневые, что первый уровень - всегда ресурс, второй и далее уровень - ID сущностей, вариации возвращемых значений и кастомные действия (в зависимости от контекста или HTTP-метода), прочие параметры - стандартно через параметры запроса после вопросика.
0
|
|||||||
|
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 [ТС] | ||
|
Но может быть и что-нибудь куда более комплексное, например, действие [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 | |||||
|
Для целей апдейта сущностей есть методы PUT и PATCHPOST используется для создания сущности.т.е. [POST]/api/invoices - создаем сущность. модель для создания должна лежать в теле.[PUT]/api/invoices/42 - обновляем сущность с id=42. Модель для обновления в теле[PATCH]/api/invoices/42 - а это для мелочевки, если надо обновить не всю сущность, а некоторые свойства. Список свойств с данными можно положить в тело, а можно и в параметры запроса.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 лет - еще что-нить придумают. Calendar API, которое работает по RESTfullТынц.... Добавлено через 10 минут
1
|
|||||
|
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
|
||
| 06.02.2020, 10:25 | ||
|
kotelok, shortMode это параметр одного метода, не надо создавать два.
0
|
||
|
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
|
|||||||
| 06.02.2020, 10:56 [ТС] | |||||||
|
yurickas
Ну так а обозначеныне главные две проблемы как решать-то )? 1. Когда для сущности требуется вернуть с сервера не сущность целиком, а только пару полей в виде соответствующего 'SimpleDto'. И, возможно, ещё какуой-нибудь DTO под конкретный кусочек фронтэнда, чтобы не тянуть пол-базы каждый раз. И, желательно, не создавая для этого фэйк-сущность. 2. Когда сущность не надо обновлять/добавлять/удалять, но для неё нужно выполнить какой-то custom-action, специфичный для предметной области. Добавлено через 7 минут Например, вполне типичная задача, когда есть некий справочник:
Добавлено через 16 минут
0
|
|||||||
|
163 / 138 / 35
Регистрация: 25.11.2015
Сообщений: 910
|
||||
| 06.02.2020, 11:07 | ||||
|
Ну, есть паттерн mvvm. На стороне сервера работаем с сущностями, отдаем их вьюмодели, принимаем вьюмодели и по ним работаем с сущностями. Перевод из одного в другое проводится или ручками, или сторонними библиотеками типа Automapper. Отдавать можно и json, а можно и xml. Кому как угодно Добавлено через 5 минут Если сервер отдает json строго по модели БД, то первый краш апи который можно получить - это парсинг циклических ссылок из object в json.
1
|
||||
|
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
|
|||
| 06.02.2020, 19:02 | |||
![]() Как-то делали сервис для централизованного управления рекламой (BING, Google AdWords), у бинга вроде было две версии API в том числе bulk loading, то есть когда грузим очень много толстых(!) объектов, зато потом не пинаем сервер вообще. С тех пор и взял за основу загружать весь граф объекта, что-то скрывать первоначально, если нужно, а обновлять по кускам.
1
|
|||
|
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
|
||
| 07.02.2020, 09:37 | ||
|
Гляньте это https://cloud.google.com/kuber... ence/rest/
0
|
||
|
163 / 138 / 35
Регистрация: 25.11.2015
Сообщений: 910
|
||||
| 07.02.2020, 10:29 | ||||
|
Добавлено через 2 минуты
0
|
||||
|
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
|
|
| 07.02.2020, 20:47 | |
|
0
|
|
| 07.02.2020, 20:47 | |
|
Помогаю со студенческими работами здесь
13
RESTful вебсервис: авторизация Пример реального restful сервиса Restful API + requests JSON Получение объектов в restful-приложении RESTful API работа с actions Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
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-код на мобильном и вы увидите, что появится джойстик для управления главным героем.
. . .
|