REST API - навіщо використовувати PUT DELETE POST GET?


155

Отже, я переглядав деякі статті про створення API REST. А деякі з них пропонують використовувати всі типи HTTP-запитів: наприклад PUT DELETE POST GET. Ми створимо, наприклад, index.php і запишемо API таким чином:

$method = $_SERVER['REQUEST_METHOD'];
$request = split("/", substr(@$_SERVER['PATH_INFO'], 1));

switch ($method) {
  case 'PUT':
    ....some put action.... 
    break;
  case 'POST':
    ....some post action.... 
    break;
  case 'GET':
    ....some get action.... 
    break;
  case 'DELETE':
    ....some delete action.... 
    break;
}

Гаразд, надано - я не знаю багато про веб-сервіси (поки що). Але чи не було б простіше просто прийняти JSON- об'єкт через регулярний POSTабо GET(який би містив назву методу та всі параметри), а потім відповісти і в JSON. Ми можемо легко сериализации / десеріалізациі з допомогою РНР json_encode()і json_decode()і робити все , що ми хочемо , щоб з цими даними без необхідності мати справу з різними методами запиту HTTP.

Я щось пропускаю?

ОНОВЛЕННЯ 1:

Гаразд - переглянувши різні API та дізнавшись багато про XML-RPC , JSON-RPC , SOAP , REST Я прийшов до висновку, що цей тип API є звуковим. На насправді стек обмін в значній мірі з допомогою цього підходу на своїх сайтах , і я думаю , що ці люди знають , що вони роблять Stack обмін API .


4
Навіщо примушувати корисне навантаження JSON? Що робити, якщо немає JSON, а це звичайний старий GET?
Майк Десимоне

Відповіді:


200

Ідея RE презентаційного S tate T ransfer полягає не в тому, щоб отримати доступ до даних найпростішим можливим способом.

Ви запропонували використовувати поштові запити для доступу до JSON, що є абсолютно правильним способом доступу / маніпулювання даними.

REST - це методологія змістовного доступу до даних. Коли ви побачите запит у REST, він повинен негайно визначити, що відбувається з даними.

Наприклад:

GET: /cars/make/chevrolet

швидше за все, повернуться до списку Chevy автомобілів. Хороший файл REST може навіть включати деякі параметри виводу в рядок запитів, наприклад, ?output=jsonабо ?output=htmlякий би дозволив одержувачу вирішити, в який формат інформації повинна бути закодована.

Після недовгих роздумів про те , як розумно включити типізації даних в REST API, я прийшов до висновку , що найкращий спосіб визначити тип даних , явно було б з допомогою вже існуючого розширення файлу , такі як .js, .json, .htmlабо .xml. Відсутнє розширення файлу за замовчуванням до будь-якого формату за замовчуванням (наприклад, JSON); розширення файлу, яке не підтримується, може повернути 501 Not Implementedкод статусу .

Ще один приклад:

POST: /cars/
{ make:chevrolet, model:malibu, colors:[red, green, blue, grey] }

швидше за все, буде створено нову chevy malibu в db з відповідними кольорами. Я можу сказати, що ймовірно , що apti REST не потребує прямого зв’язку зі структурою бази даних. Це просто маскуючий інтерфейс, щоб захищати справжні дані (думати про це як про аксесуари та мутатори для структури бази даних).

Тепер нам потрібно перейти до питання про самопочуття . Зазвичай REST реалізує CRUD через HTTP. HTTP використовує GET, PUT, POSTі DELETEдля запитів.

Дуже спрощена реалізація REST могла використовувати наступне картографування CRUD:

Create -> Post
Read   -> Get
Update -> Put
Delete -> Delete

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

Це означає, що запит, такий як:

Delete: /cars/oldest

насправді можна реалізувати як:

Post: /cars/oldest?action=delete

Тоді як

Delete: /cars/id/123456

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

Кращим способом обробки вилучення oldestпредмета було б запит:

Get: /cars/oldest

і скористайтеся IDотриманими даними, щоб зробити deleteзапит:

Delete: /cars/id/[oldest id]

Проблема з цим методом /carsполягала б у тому, якщо інший елемент було додано між /oldestзапитом та коли deleteбуло видано.


3
@Andre - це сукупність кількох причин: дотримуючись інструкцій HTTP, означає, що, мабуть, у вас буде менше проблем із сумісністю, коли зміниться; використання форми HTML через POST попередить користувача про багаторазове подання одних і тих же даних (це запобігає неідентифікуючій транзакції); слідування чітко визначеній найкращій практиці - це найкраща практика. Відпочинок не визначений, маючи на увазі конкретну реалізацію, яка дозволяє використовувати його так, як вважаєте за потрібне. Я б запропонував скористатись усіма кодами помилок HTTP та методами запиту, але ви можете це робити як завгодно
zzzzBov

4
Отже, проблема з цією відповіддю (це гідна відповідь, але не повна) полягає в тому, що вона не стосується головного питання, яке він задав: Чому б ви використовували HTTP-дієслова та URI, а не користувацькі дані JSON (можливо, якийсь тип Синтаксис виклику API на основі JSON). Ви можете зробити власний синтаксис JSON таким чином, щоб він був "негайно ... помічником того, що відбувається з даними". Що ви не можете зробити, це легко використовувати вбудовані засоби та мережеві шари поверх HTTP, як ви можете з API, який дотримується всіх положень REST. Не те, що моя відповідь ідеальна, звичайно;)
Мерлін Морган-Грехем

4
@Andre: Прикладами, якими користується запис у вікі, є автентифікація, кешування та узгодження типу вмісту. Тепер, коли я думаю про це більше, ви, можливо, зможете використовувати їх із інтерфейсами стилю RPC, але спокусою буде часто реалізовувати власну систему з нуля або кодувати інтеграцію до існуючої системи. За допомогою REST ви можете використовувати вбудовану інтеграцію та керувати нею на веб-сервері. Це означає, що втрачається більше зв'язків, це означає, що вам доведеться менше реалізовувати, а ваш додаток набагато гнучкіший для зміни варіантів у майбутньому з меншим кодом та тестовим впливом.
Мерлін Морган-Грехем

10
Замість DELETE: / автомобілі / найстаріший, як щодо GET: / cars / найстаріший і далі DELETE? Таким чином, у вас є дві окремо ідентичні команди.
Ніл

3
+1; Я погоджуюся, що це хороша відповідь (я знову переглядаю це для розваги та отримання прибутку). POST: /cars/oldestбути заміною для DELETE не має великого сенсу. Щось на кшталт - POST: /cars/oldest/deleteможливо, тому я думаю, що мені більше подобається рішення Ніла. Єдина перевага, яку дає безпосереднє видалення над рішенням get-id-delete-id, - це атомність. Я хотів би отримати чітке обґрунтування бізнесу з необдуманим сценарієм, перш ніж я буду реалізовувати таке. Вам не потрібно підтримувати всі дієслова на всіх об'єктах / URL-адресах.
Мерлін Морган-Грем

39

Це питання безпеки та ремонту.

безпечні методи

Коли це можливо, вам слід використовувати «безпечні» (однонаправлені) методи, такі як GET та HEAD, щоб обмежити потенційну вразливість.

ідемпотентні методи

Коли це можливо, слід використовувати «ідентифікаційні» методи, такі як GET, HEAD, PUT та DELETE, які не можуть мати побічних ефектів і тому менш схильні / легше контролювати.

Джерело


1
Вибачте, але як ідентифікуючі методи PUT і DELETE? Вони впливають на стан сервера та його дані!
Махмуд Аль-Кудсі

27
@ Комп'ютер: Виконання того ж PUT або того ж DELETE призводить до того ж остаточного стану. Ось що означає "безвідмовний".
Ігнасіо Васкес-Абрамс

4
Для додаткового уточнення: операція F є ідентичною, якщо одноразове її застосування та кілька послідовних додатків одночасно повертають один і той же результат. Точніше F є ідентичним, якщо і лише тоді, коли F (x) = F (F (x)). Наприклад, Видалити ідентично, бо коли ви видаляєте елемент один раз або видаляєте його кілька разів, результат є однаковим: елемент видаляється лише один раз при першому видаленні або третьому додатку, і нічого не відбувається у видаленні другої чи третьої програми.
квартал

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

qartal - ваше функціональне визначення для idempotent має бути "F (X) = F (X) F (X)". Хороший спосіб це висловити.
Джерард ONeill

26

Коротше кажучи, REST підкреслює іменники над дієсловами. Коли ваш API стає складнішим, ви додаєте більше речей, а не більше команд.


2
У мене було трохи проблем із тим, щоб обернути голову навколо цього. Це повідомлення ( lornajane.net/posts/2013/… ) про те, що дієслово повинно надходити з HTTP-запиту, щоб URI тоді містив лише іменники, очистив його для мене
icc97

9

Ви запитали :

чи не було б простіше просто прийняти JSON-об'єкт через звичайний $ _POST, а потім відповісти і в JSON

З Вікіпедії на REST :

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

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

Спеціальні протоколи даних (навіть якщо вони побудовані на версії стандартних, таких як SOAP або JSON), не рекомендуються, і їх слід мінімізувати, щоб вони найкраще відповідали ідеології REST.

SOAP RPC через HTTP, з іншого боку, спонукає кожного дизайнера додатків визначити нову та довільну лексику іменників та дієслів (наприклад, getUsers (), savePurchaseOrder (...)), як правило, накладених на дієслово HTTP 'POST'. Це нехтує багатьма існуючими можливостями HTTP, такими як автентифікація, кешування та узгодження типу вмісту, і може залишити дизайнера додатків переосмислити багато цих функцій у новому словнику.

Фактичні об'єкти, з якими ви працюєте, можуть бути в будь-якому форматі. Ідея полягає у повторному використанні якомога більшої кількості HTTP для викриття ваших операцій, які користувач хоче виконати на цих ресурсах (запити, управління / мутація стану, видалення).

Ви запитали :

Я щось пропускаю?

Про REST та самі синтаксиси URI / HTTP можна дізнатися набагато більше. Наприклад, деякі дієслова є ідентичними, інші - ні. Я нічого не бачив з цього приводу у вашому запитанні, тому не намагався зануритися в нього. Інші відповіді та Вікіпедія мають багато хорошої інформації.

Крім того, можна багато дізнатися про різні мережеві технології, побудовані на основі HTTP, якими ви можете скористатися, якщо використовуєте справді спокійний API. Я б почав з аутентифікації.


8

Що стосується використання розширення для визначення типу даних. Я помітив, що API MailChimp це робить, але не думаю, що це гарна ідея.

GET /zzz/cars.json/1

GET /zzz/cars.xml/1

Моє звучання як гарна ідея, але я вважаю, що "старший" підхід краще - використання заголовків HTTP

GET /xxx/cars/1
Accept: application/json

Також заголовки HTTP набагато краще для зв'язку між типами даних (якщо комусь це знадобиться)

POST /zzz/cars
Content-Type: application/xml     <--- indicates we sent XML to server
Accept: application/json          <--- indicates we want get data back in JSON format  

4

Я щось пропускаю?

Так. ;-)

Це явище існує через єдине обмеження інтерфейсу . REST любить використовувати вже існуючі стандарти замість того, щоб винаходити колесо. Стандарт HTTP вже зарекомендував себе як масштабований (Інтернет працює деякий час). Чому ми повинні виправити щось, що не порушено ?!

Примітка: Єдине обмеження інтерфейсу важливо, якщо ви хочете від'єднати клієнтів від послуги. Це аналогічно визначенню інтерфейсів для класів, щоб відокремити їх один від одного. Ofc. тут єдиний інтерфейс складається з таких стандартів, як HTTP , MIME типи , URI , RDF , пов'язані дані vocabs , hydra vocab тощо.


2

Гарна семантика важлива в програмуванні.

Використання додаткових методів, окрім GET / POST, буде корисним, оскільки підвищить читабельність вашого коду та полегшить його підтримку.

Чому?

Тому що ви знаєте, що GET отримає дані з вашої програми. Ви знаєте, що POST додасть нові дані до вашої системи. Ви знаєте, що PUT буде оновлювати. DELETE видалить рядки тощо тощо,

Я зазвичай структурую свої RESTFUL Web Services так, що у мене є зворотний виклик функції, який називається тим же самим, що і метод.

Я використовую PHP, тому я використовую function_exists (я думаю, це називається). Якщо функції не існує, я кидаю 405 (МЕТОД НЕ ДОЗВОЛЕНО).


2

Білл Веннерс: У своєму дописі на блозі під назвою "Чому REST не вдалося", ви сказали, що нам потрібні всі чотири HTTP-дієслова - GET, POST, PUT і DELETE - і скаржилися, що постачальники браузерів тільки GET і POST. "Чому нам потрібні всі чотири дієслова? Чому недостатньо GET і POST?

Елліотта Расті Гарольд: У HTTP є чотири основні методи: GET, POST, PUT та DELETE. GET використовується більшість часу. Він використовується для всього безпечного, що не викликає побічних ефектів. GET може бути закладений у закладки, кешований, пов'язаний, переданий через проксі-сервер. Це дуже потужна операція, дуже корисна операція.

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

PUT і DELETE знаходяться посередині між GET і POST. Різниця між PUT або DELETE і POST полягає в тому, що PUT і DELETE є * idempotent, тоді як POST - ні. PUT і DELETE при необхідності можна повторити. Скажімо, ви намагаєтеся завантажити нову сторінку на сайт. Скажіть, що ви хочете створити нову сторінку за адресою http://www.example.com/foo.html, тож ви вводите свій вміст, і ви надсилаєте його за цією URL-адресою. Сервер створює цю сторінку за вказаною вами URL-адресою. Тепер припустимо, з якоїсь причини ваше мережеве з'єднання впаде. Ви не впевнені, чи отримав запит чи ні? Можливо, мережа повільна. Можливо, виникла проблема з проксі-сервером. Тож цілком нормально спробувати ще раз чи ще раз - скільки завгодно разів. Оскільки ВСТАВКА одного і того ж документа в одну і ту ж URL-адресу десять разів не відрізнятиметься від розміщення одного разу. Те саме стосується DELETE. Ви можете ВИДАЛИТИ щось десять разів, і це те саме, що видалити його один раз.

Навпаки, POST може спричинити що-небудь інше. Уявіть, що ви виходите з інтернет-магазину, натиснувши кнопку купити. Якщо ви знову надішлете цей запит на пошту, ви можете вдруге придбати все у кошику. Якщо ви надішлете його ще раз, ви купили його втретє. Ось чому браузери повинні бути дуже обережними щодо повторення операцій POST без явної згоди користувача, оскільки POST може спричинити дві речі, якщо ви робите це двічі, три речі, якщо ви робите це три рази. У режимі PUT і DELETE велика різниця між нульовим запитом і одним, але різниці між одним запитом і десятьма немає.

Будь ласка, відвідайте URL для отримання детальної інформації. http://www.artima.com/lejava/articles/why_put_and_delete.html

Оновлення:

Ідентифіковані методи Ідентичний потенціал HTTP - це метод HTTP, який можна викликати багато разів без різних результатів. Не має значення, чи метод викликається лише один раз, або десять разів. Результат повинен бути однаковим. Знову ж таки, це стосується лише результату, а не самого ресурсу. Це все ще може бути маніпульовано (як-от часова мітка оновлення, за умови, що ця інформація не поділяється в (поточному) представленні ресурсів.

Розглянемо наступні приклади:

a = 4;

a ++;

Перший приклад - idempotent: незалежно від того, скільки разів ми виконуємо це твердження, а завжди буде 4. Другий приклад не є ідентичним. Виконання цього 10 разів призведе до іншого результату, як при запуску 5 разів. Оскільки обидва приклади змінюють значення a, обидва є безпечними методами.


1
На прикладі нової сторінки, чи не слід таким чином використовувати POST, тоді як PUT для оновлення? Створення нової сторінки - це процес, який дає новий результат кожен раз, тоді як одне і те ж редагування може бути повторене в будь-якій кількості разів, видаючи один і той же результат кожен раз. Хоча приємне фразування та пояснення.
Спірито

0

В основному REST - це ( wiki ):

  1. Архітектура клієнт-сервер
  2. Без громадянства
  3. Кешованість
  4. Багатошарова система
  5. Код на вимогу (необов’язково)
  6. Уніфікований інтерфейс

REST - це не протокол, це принципи. Різні сечовипускання та методи - хтось так називає кращі практики.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.