REST

REST (скор. англ. Representational State Transfer, «передача репрезентативного стану») — підхід до архітектури мережевих протоколів, які надають доступ до інформаційних ресурсів. Був описаний і популяризований 2000 року Роєм Філдінгом, одним із творців протоколу HTTP. В основі REST закладено принципи функціонування Всесвітньої павутини і, зокрема, можливості HTTP. Філдінг розробив REST паралельно з HTTP 1.1 базуючись на попередньому протоколі HTTP 1.0.

Дані повинні передаватися у вигляді невеликої кількості стандартних форматів (наприклад, HTML, XML, JSON). Будь-який REST протокол (HTTP в тому числі) повинен підтримувати кешування, не повинен залежати від мережевого прошарку, не повинен зберігати інформації про стан між парами «запит-відповідь». Стверджується, що такий підхід забезпечує масштабовність системи і дозволяє їй еволюціонувати з новими вимогами.

Антиподом REST є підхід, заснований на виклику віддалених процедур (Remote Procedure Call, RPC). Підхід RPC дозволяє використовувати невелику кількість мережевих ресурсів з великою кількістю методів і складним протоколом. При підході REST кількість методів і складність протоколу суворо обмежені, що призводить до того, що кількість окремих ресурсів має бути великою.

REST — це архітектурний стиль для розподілених гіпертекстових систем.[1]

Архітектурні обмеження

REST, як і кожен архітектурний стиль відповідає ряду архітектурних обмежень (англ. architectural constraints). Це гібридний стиль який успадковує обмеження з інших архітектурних стилів.[1]

Клієнт-сервер

Перша архітектура від якої він успадковує обмеження — це клієнт-серверна архітектура. Її обмеження вимагає розділення відповідальності[en] між компонентами, які займаються зберіганням та оновленням даних (сервером), і тими компонентами, які займаються відображенням даних на інтерфейсі користувача та реагування на дії з цим інтерфейсом (клієнтом). Таке розділення дозволяє компонентам еволюціонувати незалежно.

Відсутність стану

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

Обмеження "відсутність стану" не означає, що архітектура REST дозволяє будувати лише системи, в яких немає стану[en]. Відсутність стану означає, що сервер не знає про стан клієнта і не повинен запам'ятовувати послідовність здійснених до нього запитів, тому що кожен з них є незалежним. Коли клієнт, наприклад, запитує головну сторінку сайту, сервер відповідає на запитання і забуває про клієнта. Клієнт може залишити сторінку відкритою протягом кількох років, перш ніж натиснути посилання, і тоді сервер відповість на інший запит. Тим часом сервер може відповідати на запити інших клієнтів, або нічого не робити — для клієнта це не має значення.

Таким чином, наприклад дані про стан сесії (користувача, який автентифікувався) зберігаються на клієнті і передаються з кожним запитом. Це покращує масштабовність, бо сервер після закінчення обробки запиту може звільнити всі ресурси, задіяні для цієї операції, без жодного ризику втратити цінну інформацію. Також спрощується моніторинг і зневадження, бо для того аби розібратись у тому, що відбувається в певному запиті, досить подивитись лише на цей запит. Збільшується надійність, бо помилка в одному запиті не зачіпає інші.[2]

Мінусом цього обмеження є те, що знижується продуктивність через те, що в кожен запит тепер доводиться додавати дані сесії з клієнта. Також збереження стану на різних клієнтах важче підтримувати, бо реалізації клієнтів можуть відрізнятись, тоді як середовище сервера повністю під контролем розробника.[3]

Кешування

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

Рання архітектура веб, створена Тімом Бернерсом-Лі відповідала цим трьом обмеженням — клієнт-сервер без стану з підтримкою кешування.[4] Проте, стиль REST додає ще додаткові обмеження.

Однорідний інтерфейс

Всі компоненти в архітектурі REST підтримують однорідний інтерфейс. Це зменшує зв'язність між компонентами і сервісами які вони надають і дозволяє нескладно змінювати компоненти при потребі.[5] Це досягається кількома точнішими обмеженнями:

  • ідентифікація ресурсів: URI запит повинен точно визначати ресурс, що очікується та якого формату повинна бути відповідь. У відповідь на запит клієнту надається представлення ресурсу. Ресурси концептуально відділені від представлення. Наприклад, сервер може надсилати дані із бази даних в форматі HTML, XML або JSON, жоден з яких не є типом даних, що зберігаються всередині сервера.
  • маніпуляція ресурсами через представлення: якщо клієнт має представлення ресурсу, включаючи метадані, він має достатньо інформації, щоб модифікувати або видаляти цей ресурс.
  • самоописові повідомлення: кожне повідомлення має містити достатньо інформації для його обробки. Наприклад, обробник (parser), що використовується для розшифровки даних, може бути вказаний у списку MIME типів.
  • гіпермедіа як рушій стану застосунку (HATEOAS): Клієнт, що має доступ до REST сервісу, повинен отримати всі наявні сервіси та методи за допомогою гіперпосилань.

Шари абстракції

Наступним обмеженням для REST є поділ на шари абстракції. Кожен компонент потрапляє в якийсь шар і спілкується лише з компонентами в шарі під ним або в шарі над ним. Обмеження знання системи одним шаром зменшує складність компонентів.[6]

Запитування коду

Останнім архітектурним обмеженням в REST є те що клієнти повинні дозволяти розширювати свою функціональність дозволяючи завантаження додаткового коду (code on demand[en]) в формі аплетів чи скриптів. Це спрощує клієнти, дозволяючи не реалізовувати всі необхідні функції попередньо. Щоправда це необов'язкове обмеження, і якщо воно не дає переваг для конкретного застосування, то його не обов'язково реалізовувати. Наприклад, дозвіл завантаження стороннього коду може бути не бажаним з точки зору безпеки.[7]

Архітектурні елементи

Елементи даних

Компоненти REST системи спілкуються, передаючи один одному представлення ресурсу в форматі, що обирається з оновлюваного набору стандартних форматів даних. Формат обирається динамічно відповідно до бажань компонента-клієнта і можливостей сервера. Чи представлення має той самий формат, що й сам ресурс, чи є результатом якогось перетворення — це деталь реалізації, яка ховається за інтерфейсом.[8]

Ресурс

Ресурс — це ключовий елемент даних в REST. Ресурсом може бути що завгодно що можна назвати: якийсь документ (наприклад зображення), динамічне значення (наприклад погода у Львові), щось з реального світу (наприклад працівник компанії). Але якщо точніше, то ресурс  — це функція приналежності що відображає моменти в часі на множину однотипних сутностей чи значень. Множина може бути порожньою, тобто REST дозволяє посилання на якийсь об'єкт якого ще не існує.[9]

Ресурс може бути динамічним, наприклад ресурс «стаття про REST у вікіпедії» час від часу оновлює свій вміст, а може бути статичним, і після появи ніколи не змінювати свого значення, наприклад «перша версія статті про REST у вікіпедії». У REST такі два ресурси вважаються різними, хоча в певний момент часу вони можуть вказувати на одну й ту ж сутність. Єдине що важливо — семантика відображення імені ресурсу на його вміст.[10]

Ідентифікатор ресурсу

Для того, щоб посилатись на ресурси, використовуються ідентифікатори ресурсів. Компонент, який надав ресурсу ідентифікатор і дозволяє звертатись до нього за цим ідентифікатором, відповідає за збереження функції приналежності незмінною. Якість ідентифікатора залежить від якості компонента, який цей ідентифікатор надає, тому деякі ідентифікатори стають «мертвими посиланнями», коли інформацію переміщують або знищують.[11]

Приклади ідентифікаторів ресурсу: URL, URN.

Представлення

Представлення (англ. representation) — це послідовність байтів та метадані представлення, для того щоб описати ці байти. Часто, представлення називають документом, файлом, повідомленням HTTP тощо

Приклади представлення: фотографія JPEG, документ HTML. Приклад метаданих представлення — тип медіа, час останньої зміни.

Метадані також можуть бути не лише в представлення ресурсу, а й в самого ресурсу. Прикладами метаданих ресурсу є посилання на джерело, <link rel="alternates" ... />[12], заголовок HTTP vary[13].[9]

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

Також, контрольні дані, включені в запити чи відповіді, можуть керувати поведінкою кешу.[11] Прикладом таких контрольних даних можуть бути заголовки HTTP if-modified-since та cache-control.

Формат даних представлення називають типом медіа (англ. media type). Одні типи медіа краще підходять для автоматичної обробки, інші — для того щоб бути показаними користувачу. Композитні типи медіа можуть використовуватись для того, аби поєднати кілька видів представлення в одному.

Від формату даних дуже залежить латентність застосунку, яку сприймає користувач. Наприклад, браузер може почати показувати сторінку ще до того, як завантажиться ввесь HTML, це збільшує видиму швидкість роботи.[14]

Конектори

Конектори надають інтерфейс для комунікації компонентів, приховуючи реалізації ресурсів та механізм комунікації.

Конектори подібні на віддалений виклик процедур, але з певними нюансами щодо передачі параметрів та результату виклику. Параметри складаються з ідентифікатора ресурсу, контрольних даних та необов'язково, представлення. Результат — з контрольних даних відповіді і представлення. Можна абстрагуватись і вважати такий виклик синхронним, але насправді передача даних відбувається потоково, тому обробку даних можна починати ще до того як отримані всі дані, таким чином зменшуючи латентність.

Двома найважливішими типами конекторів є клієнт і сервер. Відмінністю між ними є те що клієнт ініціює запит, в той час як сервер очікує запитів і відповідає на них даючи доступ до своїх сервісів. Компонент може містити одночасно як серверні так і клієнтські конектори.[15]

Додатковим типом конектора є кеш. Кеш може бути як клієнтським, для уникнення зайвих запитів, так і серверним — для уникнення зайвого обчислення відповіді на запит. Тому що інтерфейс однорідний, кеш легко може дізнатись чи запит можна кешувати. За замовчуванням, відповідь на запит отримання ресурсу можна кешувати, а запити зміни ресурсу — ні. Проте ці замовчування можна перевантажити контрольними даними.[16]

Резолвер (англ. resolver) — це ще один тип конектора, який перетворює ідентифікатори ресурсів в інформацію про мережеві адреси необхідну компонентам щоб отримати цей ресурс. Наприклад в URI міститься доменне ім'я, і для доступу до відповідного домену, потрібно дізнатись в DNS-сервера адресу. Тому в цьому випадку система DNS грає роль резолвера.[16] Використання одного чи кількох резолверів може збільшити життєздатність ідентифікатора ресурсу, через те що він не вказує напряму на фізичне розташування ресурсу яке може змінитись.

Останньою формою конектора є тунель, який просто проводить запити через межу системи, наприклад, через фаєрвол. Причиною, через яку тунелі включено до архітектури REST, а не закрито абстракцією мережі, є те, що певні компоненти можуть перетворюватись на тунелі за запитом. Наприклад тунель HTTP[en] активується при отриманні запиту з методом CONNECT.

Компоненти

Семантика протоколу HTTP

Типове використання HTTP методів:

HTTP методи
URL GET PUT PATCH POST DELETE
Колекція https://api.example.com/resources/ Повертає URI та можливо інші деталі ресурсів колекції. Замінює одну колекцію іншою. Зазвичай не використовують Створює новий ресурс в колекції. URI для нового ресурсу застосунок призначає автоматично та зазвичай повертає у відповіді.[17] Видаляє всю колекцію.
Ресурс https://api.example.com/resources/item17 Повертає представлення ресурсу колекції. Замінює певний ресурс колекції, і якщо він не існує, створює його. Оновлює певний ресурс колекції. Зазвичай не використовують Видаляє певний ресурс колекції.


Хоча ресурс може бути яким завгодно, дії, які можна виконувати над ресурсом, визначаються повідомленнями, які визначено стандартним протоколом. В системі WWW цей протокол — HTTP, але існують REST-архітектури на основі й інших протоколів.

Стандарт HTTP визначає 8 типів повідомлень.

Найчастіше використовують 4 з них:

  • GET — отримати представлення ресурсу
  • DELETE — знищити ресурс
  • POST — створити новий ресурс на місці даного використавши передане представлення
  • PUT — замінити стан поточного ресурсу станом, що описується переданим представленням

Ці використовуються, щоб дослідити API:

  • HEAD — отримати заголовки, які б відсилались разом з представленням цього ресурсу, але не саме представлення.
  • OPTIONS — визначити список методів, на які цей ресурс відповідає.

Інші два методи, CONNECT та TRACE, використовуються лише для HTTP-проксі[18].

Існує також дев'ятий метод, щоправда, описаний не в HTTP, а в додатку RFC 5789:

PATCH — змінити лише частину цього ресурсу на основі даного представлення. Якщо якась частина ресурсу не згадується в переданому представленні — не чіпати її. Це знижує кількість інформації, яку потрібно передавати.

Ще два методи описуються в пропозиції до стандарту «Internet-Draft „snell-link-method“»:

  • LINK — прив'язати певний ресурс до цього
  • UNLINK — відв'язати ресурс від цього

Методи GET, PUT та DELETE — ідемпотентні, що означає, що незалежно від того, скільки разів ви виконаєте операцію, яку вони просять, — ви отримаєте той самий результат. Звісно, спершу DELETE поверне 204 No Content, а потім 404 Not Found, але ресурсу не буде, що після одного видалення, що після десяти. Ідемпотентність є дуже важливою в мережі, де ви не знаєте, чи досяг запит успіху, і, не отримавши відповіді, надсилаєте його ще раз. POST — не ідемпотентний, тобто, відправивши POST на створення повідомлення кілька разів, ви отримаєте кілька повідомлень.[19]

URI Templates[en] описуються в RFC 6570, і виглядають так[20]:

https://uk.wikipedia.org/w/index.php?search={search}

Див. також

Примітки

  1. а б Fielding, 2000, с. 76.
  2. Fielding, 2000, с. 78.
  3. Fielding, 2000, с. 79.
  4. Fielding, 2000, с. 80.
  5. Fielding, 2000, с. 81.
  6. Fielding, 2000, с. 82.
  7. Fielding, 2000, с. 84.
  8. Fielding, 2000, с. 85.
  9. а б Fielding, 2000, с. 88.
  10. Fielding, 2000, с. 89.
  11. а б Fielding, 2000, с. 90.
  12. Архівована копія. Архів оригіналу за 27 грудня 2016. Процитовано 14 лютого 2017.{{cite web}}: Обслуговування CS1: Сторінки з текстом «archived copy» як значення параметру title (посилання)
  13. RFC7231, section 7.1.4. Архів оригіналу за 25 травня 2017. Процитовано 14 лютого 2017.
  14. Fielding, 2000, с. 92.
  15. Fielding, 2000, с. 94.
  16. а б Fielding, 2000, с. 95.
  17. Esempio di API REST. There Is No Right Way. 16 maggio 2012. Процитовано 31 luglio 2014. {{cite web}}: Проігноровано невідомий параметр |cognome1= (можливо, |last1=?) (довідка); Проігноровано невідомий параметр |nome1= (можливо, |last1=?) (довідка)
  18. Richardson, Amundsen та Ruby, 2013, с. 33.
  19. Richardson, Amundsen та Ruby, 2013, с. 36.
  20. Richardson, Amundsen та Ruby, 2013, с. 49.

Література

Посилання