Чому REST Api не дотримується схеми дизайну фасадів


9

Порівнюючи структуру REST [api] з моделлю ОО, я бачу такі схожість:

Обидва:

  • Орієнтовані на дані

    • REST = Ресурси
    • ОО = об’єкти
  • Об'ємна робота навколо даних

    • REST = оточувати VERBS (Get, Post, ...) навколо ресурсів
    • OO = сприяти роботі навколо об'єктів шляхом інкапсуляції

Однак, хороші практики OO не завжди стоять на REST apis, наприклад, при спробі застосувати шаблон фасаду, наприклад: у REST у вас немає 1 контролера для обробки всіх запитів І ви не приховуєте внутрішню складність об'єкта.

Просте об'єктне відношення між двома поняттями

Аналогія між ОО та REST

Навпаки, REST сприяє публікації ресурсів усіх відносин з ресурсом та інших принаймні у двох формах:

  1. через ієрархію відносин ресурсів (Контакт ідентифікатора 43 складається з адреси 453): /api/contacts/43/addresses/453

  2. через посилання у відповіді REST json:

>> GET /api/contacts/43
<< HTTP Response {
   id: 43, ...
   addresses: [{
      id: 453, ...
   }],
   links: [{
      favoriteAddress: {
          id: 453
      }
   }]
}

Основна складність, прихована об'єктомA

Повертаючись до OO, схема дизайну фасаду відповідає Low Couplingміж об'єктомA та його " клієнтомBB об'єкта ", а також High Cohesionщодо цього об'єктаA та його внутрішньої композиції об'єкта ( objectC , objectD ). З Objecta інтерфейс, це дозволяє розробнику , щоб обмежити вплив на objectB з Objecta внутрішніх змін (в objectC і objectD ), до тих пір , як Objecta API (операцій) по - , як і раніше дотримується.

У REST дані (ресурс), відносини (посилання) та поведінка (дієслова) вибухають у різних елементах і доступні в Інтернеті.

Граючи з REST, я завжди впливаю на зміни коду між моїм клієнтом та сервером: Тому що я маю High Couplingміж моїми Backbone.jsзапитами та Low Cohesionміж ресурсами.

Я ніколи не зрозумів, як дати свою Backbone.js javascript applicationугоду з « REST ресурсів і особливості » відкриття сприяло REST зв'язків. Я розумію, що WWW призначений для обслуговування декількох серверів, і що елементи OO повинні були підірватись, щоб їх обслуговувало багато хостів, але для простого сценарію, наприклад "збереження" сторінки, що показує контакт з її адресами, Я закінчую:

GET /api/contacts/43?embed=(addresses)
[save button pressed]
PUT /api/contacts/43
PUT /api/contacts/43/addresses/453

що приводить мене до переміщення атомної трансакційної відповідальності за збереження дії на додатках браузерів (оскільки два ресурси можна вирішувати окремо).

Зважаючи на це, якщо я не можу спростити свою розробку (шаблони дизайну фасаду не застосовуються) і якщо я принесу більшу складність для свого клієнта (обробка транзакційного атомного збереження), де користь бути RESTful?


1
Дозвольте мені зрозуміти. Ви говорите, що вам потрібно оновити Контакт "вбудованою" (композицією) адресою, використовуючи два дзвінки REST, один для контакту та інший для його адреси. У вас є Фасад для обробки оновлення контактів. У чому полягає проблема з PUT /api/contacts/43каскадом оновлень внутрішніх об'єктів? У мене було багато таких інтерфейсів API (головна URL-адреса читає / створює / оновлює "ціле", а додаткові URL-адреси оновлюють шматки). Просто переконайтеся, що ви не оновлюєте адресу, коли не потрібні зміни (з міркувань продуктивності).
Anthony Accioly

@AnthonyAccioly, ти правильно зрозумів. Я спробував уточнити своє запитання, додавши кілька зображень. Ваша пропозиція хороша, і до цього я також дійшов висновку: вручну керуючи моїм запитом та використовуючи вбудований об’єкт, щоб надіслати лише один запит на збереження атомного мого оновлення. І все-таки: Чому все в REST відштовхує мене від якості OO або примусового виконання (інкапсуляція, ...) шляхом вирівнювання моєї моделі (маючи на увазі багато контролерів). Використання вашого рішення дає 1 атомне оновлення. Використання вашого рішення не приносить розробнику нової відповідальності та не застосовує правил, які б заважали йому робити це.
Ален

Лише зауваження: згадані вами "відносини ієрархії ресурсів" - це питання про те, як можна вирішити кодувати інформацію про відносини в ідентифікаторі (у цьому випадку URL). Я не впевнений, що ця експозиція інформації є частиною REST або щось, що вона сприяє, просто рішення, яке кожен приймає самостійно, коли придумує URL-адреси системи. Якщо ви вірите в інше, чи є у вас будь-які згадки про Роя Філдінга, який обговорював це питання як частину REST?
Тіаго Сільва

Відповіді:


7

Я думаю, що об'єкти побудовані правильно лише на основі узгодженої поведінки, а не навколо даних. Я спровокую і скажу, що дані майже не мають значення в об'єктно-орієнтованому світі. Насправді, можливо, і іноді звичайним є об'єкти, які ніколи не повертають дані, наприклад, "протоколи журналу", або об'єкти, які ніколи не повертають передані їм дані, наприклад, якщо вони обчислюють статистичні властивості.

Не будемо плутати PODS (які є трохи більше, ніж структури), а реальні об'єкти, що мають поведінку (як Contactsклас у вашому прикладі) 1 .

PODS - це зручність, яка використовується для спілкування із сховищами та бізнес-об'єктами. Вони дозволяють коду бути безпечним для типу. Ні більше, ні менше. Бізнес-об’єкти, з іншого боку, надають конкретні форми поведінки , як-от перевірка ваших даних, зберігання або використання їх для обчислення.

Отже, поведінка - це те, що ми використовуємо для вимірювання "згуртованості" 2 , і досить просто побачити, що у вашому прикладі об'єкта є деяка згуртованість, навіть якщо ви показуєте лише методи маніпулювання контактами верхнього рівня та ніяких методів маніпулювання адресами.

Щодо REST, ви можете бачити служби REST як сховища даних. Велика різниця в об'єктно-орієнтованому дизайні полягає в тому, що існує (майже) лише один вибір дизайну: у вас є чотири основні методи (більше, якщо HEAD, наприклад, рахувати ), і, звичайно, у вас є багато простоти з URI, щоб ви могли зробити чудовий такі речі, як передають багато ідентифікаторів і отримують більшу структуру назад. Не плутайте дані, які вони передають, з виконаними ними операціями . Згуртованість та з'єднання стосуються коду, а не даних .

Зрозуміло, що послуги REST мають високу згуртованість (кожен спосіб взаємодії з ресурсом знаходиться в одному місці) та низьку взаємодію (кожне сховище ресурсів не вимагає знань інших).

Основним фактом залишається, однак, REST - це по суті єдиний зразок сховища для ваших даних. Це має наслідки, оскільки це парадигма, побудована на основі легкої доступності на повільному носії, де висока вартість "чаті": клієнти, як правило, хочуть виконати якомога менше операцій, але в той же час отримують лише необхідні дані. . Це визначає, наскільки глибоке дерево даних ви збираєтеся відправити назад.

У (правильному) об'єктно-орієнтованому дизайні будь-яке нетривіальне додаток буде робити набагато складніші операції, наприклад, за допомогою композиції. Ви можете мати методи для виконання більш спеціалізованих операцій з даними - що повинно бути так, оскільки, хоча REST є протоколом API, OOD використовується для побудови цілих програм, що стоять перед користувачами! Ось чому вимірювання згуртованості та зв'язку є основними в OOD, але майже несуттєвими для REST.

На сьогодні вже очевидно, що аналіз дизайну даних за допомогою концепцій ОО - це не надійний спосіб її вимірювання: це як порівняння яблук та апельсинів!

Насправді, виявляється, що переваги RESTful є (здебільшого) викладеними вище: це хороший зразок для простих API на повільному середовищі. Це дуже кешируемо і розширюється. Він має тонкозернистий контроль над балакучістю тощо.

Я сподіваюся, що це відповість на ваше (досить багатогранне) питання :-)


1 Ця проблема є частиною більшого набору проблем, відомих як невідповідність об'єктно-реляційного імпедансу . Прихильники ОРМ, як правило, знаходяться в таборі, який досліджує схожість між аналізом даних та аналізом поведінки, але ORM піддаються критиці запізнення, оскільки вони, здається, не реально вирішують невідповідність імпедансу і вважаються непрохідними абстракціями .

2 http://en.wikipedia.org/wiki/Cousion_(computer_science)


Ви маєте рацію, мені важко було підірвати своє питання в багатьох аспектах, щоб визначити конкретний момент, оскільки питання стосується "неправильного" висновку, заснованого на накопиченні цих аспектів. Я зараз спробую відповісти на ваші моменти у багатьох коментарях.
Ален

[текст 1] Я використав слово "дані", щоб абстрагуватися від OO та REST світу. Яке слово ви використали б для абстрактних властивостей OO та структури даних у REST?
Ален

@Alain "дані" чудово, але моя думка - не плутати PODS та бізнес-об'єкти. Коли ми говоримо про OOD, ми зазвичай говоримо про друге. Перші - це зручність, і можна майже так само легко придумати словник, структуру чи кортеж.
Sklivvz

Так, я згоден, я використовую Backbone.js, де для збереження моделі використовується проста структура json. Тут текст відображає мій фактичний досвід кодування.
Ален

[текст 3] Це для мене нове. Я думав, що згуртованість вимірюється кількістю часових методів використання певного відношення ... Я вважаю за краще ваш спосіб його перегляду.
Ален

1

Зважаючи на це, якщо я не можу спростити свою розробку (шаблони дизайну фасаду не застосовуються) і якщо я принесу більшу складність для свого клієнта (обробка транзакційного атомного збереження), де користь бути RESTful?

Відповідь на "де користь бути ВІДКРИТИМ?" ретельно аналізується та пояснюється тут: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

Плутанина в цьому запитанні полягає в тому, що справа не в характеристиках REST і тому, як з ними впоратися, але припускаючи, що дизайн URL-адрес, які ви створили для вашої прикладної системи, має щось спільне з тим, щоб бути RESTful. Зрештою, REST стверджує, що є речі, які називаються ресурсами, і повинен бути наданий ідентифікатор для тих, на які потрібно посилатися, але це не диктує, що, скажімо, сутності у вашій моделі ER повинні мати 1-1 відповідність із створеними вами URL-адресами. (ні те, що URL-адреси не повинні кодувати кардинальність відносин ER в моделі).

Що стосується контактів та адрес, ви могли б визначити ресурс, який спільно представляє ці відомості як єдину одиницю, хоча ви, можливо, захочете витягнути та зберегти цю інформацію у, скажімо, різних реляційних таблицях БД, коли б вони були PUT або POSTed .


1

Це тому, що фасади - це «хижість»; Ви повинні поглянути на "абпікацію api" та "api chaining". Api - це поєднання двох наборів функціональності: вводу / виводу та управління ресурсами. Місцево введення-виведення є нормальним, але в розподіленій архітектурі (наприклад, проксі, ворота api, черга повідомлень тощо) спільно вводиться введення-виведення, і таким чином дані та функціональні можливості дублюються та заплутуються. Це призводить до проблем архітектури наскрізних проблем. Це чує ВСІ існуючі апіси.

Єдиний спосіб вирішити це - абстрагувати функціонал вводу-виводу для API до обробника до / після публікації (наприклад, handlerIntercepter навесні / Grails або фільтр у Rails), щоб функціональність могла використовуватися як монада та поділятися між примірниками та зовнішніми інструментальне обладнання. Дані для запиту / відповіді також повинні бути екстерналізовані в об'єкті, щоб вони також могли бути спільними та перезавантаженими.

http://www.slideshare.net/bobdobbes/api-abstraction-api-chaining


0

Якщо ви розумієте свою послугу REST або взагалі будь-який API, як додатковий інтерфейс, піддається клієнтам, щоб вони могли запрограмувати ваш контролер (и) через нього, це раптом стає просто. Послуга - це не що інше, як додатковий рівень, що відповідає вашій логіці бізнесу.

Іншими словами, вам не доведеться розділяти логіку бізнесу між кількома контролерами, як це було зроблено на малюнку вище, і що ще важливіше, ви не повинні. Структурам даних, які використовуються для обміну даними, не потрібно відповідати структурам даних, які ви використовуєте внутрішньо, вони можуть бути зовсім іншими.

Це є сучасним і широко прийнятим, що це погана ідея вводити будь-яку логіку бізнесу в код інтерфейсу користувача. Але кожен інтерфейс - це лише своєрідний інтерфейс (Я в інтерфейсі) для управління логікою бізнес. Отже, здається очевидним, що це також погана ідея розміщувати будь-яку бізнес-логіку на рівні обслуговування REST або будь-який інший рівень API.

Концептуально кажучи, між інтерфейсом інтерфейсу та API сервісу не так багато різниці.


Я погоджуюся з поняттям шару, але що ви маєте на увазі під "програмуванням вашого контролера через нього"?
Ален

1
Хочу наголосити на тому, що сам контролер - справжня служба. Інтерфейс, обгорнутий навколо всього, є лише засобом чогось досягти. Будь-який інтерфейс існує так, щоб полегшити доступ до завершеного функціонування, так чи інакше. GUI робить це для користувачів людей, сервісний API використовується клієнтами. Обидві цільові аудиторії хочуть досягти чогось із речами, загорнутими за інтерфейс. Я погоджуюся, що "програма" може бути не найкращою формулюванням для цього, але "керувати контролерами" звучить ніяково ;-)
JensG
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.