REST API - зачем использовать PUT DELETE POST GET?


155

Итак, я просматривал некоторые статьи по созданию REST API. И некоторые из них предлагают использовать все типы 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 Exchange API .


4
Зачем использовать JSON? Что делать, если нет JSON, а это обычный GET?
Майк ДеСимоне

Ответы:


200

Идея RE презентационный S Тейт T ransfer не о доступе к данным в наиболее простом способе.

Вы предложили использовать почтовые запросы для доступа к JSON, который является совершенно допустимым способом доступа к данным и манипулирования ими.

REST - это методология значимого доступа к данным. Когда вы видите запрос в REST, он должен немедленно следить за тем, что происходит с данными.

Например:

GET: /cars/make/chevrolet

скорее всего собираюсь вернуть список шеви авто. Хороший API 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] }

скорее всего, собирается создать новый шевроле малибу в БД со связанными цветами. Я говорю скорее всего, поскольку REST API не должен быть напрямую связан со структурой базы данных. Это просто маскирующий интерфейс, обеспечивающий защиту истинных данных (представьте, что это средства доступа и мутаторы для структуры базы данных).

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

Очень упрощенная реализация REST может использовать следующее отображение CRUD:

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

Существует проблема с этой реализацией: публикация определяется как неидемпотентный метод. Это означает, что последующие вызовы одного и того же метода Post приведут к различным состояниям сервера. Get, Put и Delete, являются идемпотентными; Это означает, что их многократный вызов должен привести к одинаковому состоянию сервера.

Это означает, что запрос, такой как:

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
@ И это сочетание нескольких причин: следование рекомендациям HTTP означает, что у вас (вероятно) будет меньше проблем с обратной совместимостью, когда что-то изменится; использование html-формы через POST предупредит пользователя о множественных отправках одних и тех же данных (это предотвратит неидемпотентную транзакцию); следовать четко определенной передовой практике - это, пожалуй, лучшая практика. Отдых не определен с конкретной реализацией, что позволяет вам использовать его по своему усмотрению. Я бы предложил воспользоваться всеми кодами ошибок HTTP и методами запроса, но вы можете делать это как хотите
zzzzBov

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

4
@Andre: примеры, используемые в вики, - это аутентификация, кэширование и согласование типов контента. Теперь, когда я больше об этом думаю, вы можете использовать их с интерфейсами в стиле RPC, но часто возникает искушение реализовать собственную систему с нуля или создать интеграцию с существующей системой. С REST вы можете использовать встроенную интеграцию и администрировать ее на веб-сервере. Это означает более слабую связь, что означает, что вам нужно реализовать меньше, и означает, что ваше приложение становится более гибким, чтобы изменять параметры в будущем с меньшим количеством кода и влиянием на тестирование.
Мерлин Морган-Грэм

10
Вместо DELETE: / cars / old, как насчет GET: / cars / old, за которым следует 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
@Computer: выполнение одного и того же PUT или одного и того же DELETE приводит к тому же конечному состоянию. Вот что значит «идемпотент».
Игнасио Васкес-Абрамс

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

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

qartal - ваше функциональное определение идемпотента должно быть «F (X) = F (X) F (X)». Хороший способ выразить это все же.
Джерард ONeill

26

Короче говоря, REST подчеркивает существительные над глаголами. Поскольку ваш API становится более сложным, вы добавляете больше вещей, чем команд.


2
У меня были проблемы с тем, чтобы обдумать это. Этот пост ( lornajane.net/posts/2013/… ) о том, что глагол должен исходить из HTTP-запроса, так что URI должен содержать только существительные, прояснил мне его немного
icc97

9

Вы спросили :

не проще ли будет принять объект JSON через обычный $ _POST, а затем ответить и в JSON

Из Википедии на ОТДЫХЕ :

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

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

Настраиваемые протоколы данных (даже если они построены поверх стандартных, таких как SOAP или JSON) не рекомендуется и должны быть сведены к минимуму, чтобы наилучшим образом соответствовать идеологии REST.

SOAP RPC через HTTP, с другой стороны, рекомендует каждому разработчику приложения определить новый и произвольный словарь существительных и глаголов (например, getUsers (), savePurchaseOrder (...)), обычно накладываемых на глагол HTTP «POST». Это не учитывает многие из существующих возможностей HTTP, таких как аутентификация, кэширование и согласование типов контента, и может привести к тому, что разработчик приложения заново изобретет многие из этих функций в новом словаре.

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

Вы спросили :

Я что-то упускаю?

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

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


8

Что касается использования расширения для определения типа данных. Я заметил, что MailChimp API делает это, но я не думаю, что это хорошая идея.

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 , связанные области данных , hydra vocab и т. д.


2

Хорошая семантика важна в программировании.

Использование большего количества методов помимо GET / POST будет полезно, потому что это повысит читабельность вашего кода и облегчит его обслуживание.

Зачем?

Потому что вы знаете, GET будет получать данные из вашего API. Вы знаете, что 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 * идемпотентны, а POST - нет. PUT и DELETE могут быть повторены при необходимости. Допустим, вы пытаетесь загрузить новую страницу на сайт. Скажем, вы хотите создать новую страницу на http://www.example.com/foo.htmlТаким образом, вы вводите свой контент и помещаете его по этому URL. Сервер создает эту страницу по указанному вами URL. Теперь давайте предположим, что по какой-то причине ваше сетевое соединение обрывается. Вы не уверены, запрос прошел или нет? Возможно, сеть работает медленно. Возможно, возникла проблема с прокси-сервером. Поэтому вполне нормально попробовать это снова или снова - столько раз, сколько захотите. Потому что ПОДКЛЮЧЕНИЕ одного и того же документа к одному и тому же URL-адресу десять раз ничем не отличается от размещения его один раз. То же самое верно и для удаления. Вы можете УДАЛИТЬ что-нибудь десять раз, и это то же самое, что удалить это один раз.

В отличие от POST, каждый раз может происходить что-то другое. Представьте, что вы выходите из интернет-магазина, нажав кнопку покупки. Если вы отправите этот запрос POST снова, вы можете в конечном итоге купить все в вашей корзине во второй раз. Если вы отправите его снова, вы купили его в третий раз. Вот почему браузеры должны быть очень осторожны с повторением операций POST без явного согласия пользователя, потому что POST может вызвать две вещи, если вы сделаете это дважды, и три вещи, если вы сделаете это три раза. С PUT и DELETE существует большая разница между нулевыми запросами и одним, но нет разницы между одним запросом и десятью.

Пожалуйста, посетите URL для более подробной информации. http://www.artima.com/lejava/articles/why_put_and_delete.html

Обновить:

Идемпотентные методы Идемпотентный HTTP-метод - это HTTP-метод, который можно вызывать многократно без разных результатов. Не имеет значения, если метод вызывается только один раз или десять раз. Результат должен быть таким же. Опять же, это относится только к результату, а не к самому ресурсу. Этим все еще можно манипулировать (например, отметкой времени обновления, при условии, что эта информация не используется совместно в (текущем) представлении ресурса.

Рассмотрим следующие примеры:

а = 4;

A ++;

Первый пример идемпотентен: независимо от того, сколько раз мы выполняем это утверждение, a всегда будет 4. Второй пример не идемпотентен. Выполнение этого 10 раз приведет к другому результату, как при выполнении 5 раз. Поскольку оба примера меняют значение a, оба являются небезопасными методами.


1
Что касается примера новой страницы, разве не следует использовать POST таким образом, а PUT - для обновления? Создание новой страницы - это процесс, который каждый раз выдает новый результат, в то время как одно и то же редактирование может повторяться любое количество раз, каждый раз получая один и тот же результат. Хорошая формулировка и объяснение, хотя.
Spyryto

0

В основном REST это ( вики ):

  1. Клиент-серверная архитектура
  2. безгражданство
  3. кэширование
  4. Многоуровневая система
  5. Код по запросу (необязательно)
  6. Единый интерфейс

ОТДЫХ - это не протокол, это принципы. Разные урисы и методы - у кого-то так называемые лучшие практики.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.