Привет! Я - Лера, и я — человек, который однажды понял, что прошлый опыт не помешает построить что-то новое. Эту статью я пишу для тех, кто хочет разобраться в сложных понятиях простыми словами.
Идемпотентность стала моей "любимой" темой после одного из первых собеседований, где меня попросили объяснить её так, чтобы понял кот. Тогда это было для меня вызовом, но спустя время я поняла, что вдохновение приходит из простых вещей и самый простой способ объяснить их — через примеры, которые мы видим каждый день. Надеюсь, после прочтения статьи это будет понятно не только вам, но и вашему коту, если вдруг он читает.
Вы когда-нибудь многократно нажимали на кнопку вызова лифта, стоя у дверей, которые не закрываются быстрее от вашего нетерпения? На самом деле, лифт уже понял вас с первого раза.
Это один из примеров идемпотентности — свойства, когда повторение одного и того же действия не изменяет результат. Забавно, но этот принцип не только сохраняет спокойствие лифтов, но и помогает во многих других сферах жизни и технологий. И кто знает, может знание об идемпотентности однажды избавит нас от лишних жестов и сэкономит наше время?
Идемпотентность — это когда вы делаете что-то снова и снова, но результат остаётся тем же, как если бы вы сделали это один раз. Представьте, что вы живете на 12 этаже, а лифт находится на первом. Вы нажимаете кнопку, чтобы вызвать его, и лифт приезжает к вам. Затем, даже если вы нажмете кнопку еще раз, лифт не отправится в новое путешествие вниз — он уже здесь, на вашем этаже. Это прекрасная демонстрация идемпотентности: лифт не реагирует на лишние нажатия кнопки.
Однако не все так просто в других аспектах жизни. Возьмем, к примеру, покупки в магазине. Если вы положите в корзину лимон, а затем добавите еще один, ваша корзина изменится: сначала в ней не было лимонов, а потом стало два. Этот процесс — неидемпотентный, ведь каждое действие изменяет состояние системы, или в данном случае — вашей корзины.
Давайте разберемся с идемпотентностью четырех основных HTTP-методов: GET, POST, PUT, и DELETE. На первый взгляд кажется, что идемпотентным является только метод GET, ведь он, казалось бы, не меняет состояние системы. Но не спешите с выводами — давайте подробнее рассмотрим каждый из них.
GET — этот метод как раз тот самый спокойный парень, который просто смотрит информацию, не вмешиваясь. Вы можете сколько угодно раз просить его показать одну и ту же страницу или данные, и состояние системы останется неизменным каждый раз. Например, помните момент в "Друзьях", когда Росс несколько раз подглядывал за Рейчел через глазок двери? Он мог смотреть бесконечно, но это никак не влияло на то, что происходило за дверью. Так и метод GET — он просто наблюдает, не вмешиваясь.
Теперь обратим внимание на метод PUT, который можно сравнить с переодеванием на вечеринке. Представим, что вы решили обновить свой образ, заменив футболку. Вы отправляете запрос в "гардеробную систему" вашего шкафа, выбирая новую футболку. Система обрабатывает запрос и "обновляет" ваш внешний вид.
Можно ли сказать, что этот метод меняет что-то каждый раз? На первый взгляд кажется, что да. Но давайте проверим ещё раз. Если вы отправите точно такой же запрос — снова выберите ту же футболку, — ваш внешний вид не изменится. Вы выглядите так же, как после первого "обновления". Вот и получается, что метод PUT идемпотентен: повторное применение одного и того же запроса не меняет результат.
Вспомним забавный момент из сериала "Друзья", когда Джоуи переоделся во все вещи Чендлера. Первый раз его внешний вид радикально изменился, но если бы он решил повторить этот трюк, результат остался бы прежним. Джоуи мог бы вновь надеть все те же вещи Чендлера, но внешне он выглядел бы так же, как после первой примерки. Это идеально иллюстрирует идемпотентность метода PUT — даже если действие повторить, изменения во "внешней системе" (в данном случае, в гардеробе) не произойдет.
Итак, вот интересная загадка: является ли метод DELETE идемпотентным? Подумайте секунду... Готовы разобраться?
Метод DELETE, это как большая красная кнопка "удалить" для данных на сервере. По сути, это способ сказать системе: "Этого больше не существует". Давайте посмотрим на практический пример.
Вспомните эпизод из сериала "Друзья", где Фиби, Джоуи и Моника пытались угадать, кто отец ребенка Рейчел. Моника как подсказку приносит свитер и кладет его на стол. Позже Росс заходит и забирает свой свитер. В этом случае Росс действует как метод DELETE: он убирает свитер, изменяя состояние "системы" (стола), где свитер больше не лежит. Теперь представим, что Росс входит снова, чтобы взять свитер, которого уже нет. Он обнаруживает пустой стол и уходит, не изменив ничего. Система осталась в том же состоянии, в каком была после первого удаления свитера.
Так что да, метод DELETE идемпотентен. Он делает свою работу один раз, и повторные попытки ничего не изменят — свитер уже удален, стол пуст.
Итак, перейдем к самому интересному — методу POST. Может показаться, что если такие методы, как PUT и DELETE, идемпотентны, то POST точно такой же, правда? Но давайте разберемся поподробнее.
Представьте себе Тони Старка в киновселенной Marvel с бокалом виски. Каждый его глоток уменьшает количество напитка в бокале — система меняется с каждым действием. Вот и POST, как Тони со своим виски: каждый раз, когда вы используете метод POST для отправки данных, вы вносите новую информацию или создаете новую запись в системе. Если повторить запрос POST с теми же данными, это не просто эхо предыдущего действия — это новое действие, которое может создать дубликат или дополнительное изменение в системе.
Так что нет, метод POST не идемпотентен. Он всегда добавляет что-то новое или меняет систему, точно как каждый глоток виски в бокале Тони Старка.
Теперь давайте зададим интересный вопрос: может ли метод, который изначально не идемпотентен, стать таковым? Ответ звучит как нечто из философского трактата: нет, метод по своей природе либо идемпотентен, либо нет. Однако мы можем немного "поиграть" с правилами и заставить методы вести себя как идемпотентные с помощью определенных ограничений.
Как это работает? Как мы можем искусственно симулировать идемпотентность в системах, которые изначально не предполагают такого свойства? Вот несколько методов, которые можно применять вместе или по отдельности для достижения этой цели:
1. Добавление токенов идемпотентности: Эти токены гарантируют, что повторные операции с теми же параметрами не будут обрабатываться системой как новые. Каждый запрос снабжается уникальным идентификатором, который позволяет системе распознать повторение.
Своего рода токены идемпотентности — защитники от хаоса в запросах. Представьте, что вы отправляете запрос на оплату. Вместе с данными системы прикладывают к нему специальный уникальный ключ, например, idempotency_key: "abc123". Этот ключ — как паспорт, который позволяет системе понять, что это за операция и была ли она уже выполнена.
Если запрос случайно повторится — система всё вспомнит: «О, это уже было, вот же результат». В итоге, деньги не списываются дважды, магазин не удивляется лишним операциям, а вы можете спокойно дышать. Логика проста: запрос — токен — ответ. Никаких дублей и никаких неожиданностей.
Лично у меня токены идемпотентности ассоциируются со сценой из Гарри Поттера, где школа отправляла Гарри письма о зачислении, где каждое из них помечалось как уникальное. Если письмо не доходило (спасибо Дурсли!), сова просто присылала новое, но только до тех пор, пока школа не получила ответа. Как только Гарри наконец согласился, повторные письма больше не отправлялись: система зафиксировала результат, и совы выдохнули.
Request: Первый запрос
{
"idempotency_key": "abc123",
"operation": "payment",
"amount": 100,
"currency": "USD",
"payment_method": "credit_card",
"customer_id": "cust_001"
}
Response: Первый запрос
{
"status": "success",
"transaction_id": "txn_001",
"message": "Payment processed successfully.",
"amount": 100,
"currency": "USD"
}
Первый запрос с idempotency_key: "abc123" обрабатывается нормально, создается транзакция txn_001.
Request: Повторный запрос с тем же токеном
{
"idempotency_key": "abc123",
"operation": "payment",
"amount": 100,
"currency": "USD",
"payment_method": "credit_card",
"customer_id": "cust_001"
}
Response: Повторный запрос
{
"status": "duplicate",
"transaction_id": "txn_001",
"message": "Duplicate request detected. Original transaction details returned.",
"amount": 100,
"currency": "USD"
}
Повторный запрос с тем же idempotency_key: "abc123" возвращает данные уже существующей транзакции (txn_001) без повторной обработки.
2. Настройка временного окна: Этот метод ограничивает время, в течение которого запрос может быть повторно обработан как новый. Если запрос повторяется в пределах этого окна, система рассматривает его как дубликат и не изменяет состояние системы.
Временное окно — это промежуток времени, в течение которого запросы с одними и теми же параметрами обрабатываются как повторные. Например, Вы стоите на улице, промокший и раздражённый, и дважды подряд вызываете такси, молясь, чтобы оно приехало быстрее. Система фиксирует оба запроса, но у неё есть правило: если между нажатиями прошло меньше двух минут, она не будет лишний раз искать водителя, а просто вернёт данные о вашем первом вызове.
Но стоит вам нажать "заказать" через пять минут после первой попытки — всё меняется. Система считает это новым запросом, а вы получаете свежую машину. Временное окно — это как разумный друг, который говорит: "Спокойно, всё уже устроено".
Request: Первый запрос
{
"request_id": "req_001",
"operation": "book_taxi",
"pickup_location": "ул. Ленина, д. 10",
"dropoff_location": "пр. Мира, д. 25",
"customer_id": "cust_001",
"timestamp": "2024-11-24T10:00:00Z"
}
Response: Первый запрос
{
"status": "success",
"booking_id": "booking_001",
"message": "Taxi successfully booked.",
"pickup_time": "2024-11-24T10:15:00Z"
}
Request: Повторный запрос в пределах временного окна (1 минута спустя)
{
"request_id": "req_002",
"operation": "book_taxi",
"pickup_location": "ул. Ленина, д. 10",
"dropoff_location": "пр. Мира, д. 25",
"customer_id": "cust_001",
"timestamp": "2024-11-24T10:01:00Z"
}
Response: Повторный запрос в пределах временного окна
{
"status": "duplicate",
"booking_id": "booking_001",
"message": "Duplicate request detected. Returning details of the existing booking.",
"pickup_time": "2024-11-24T10:15:00Z"
}
Request: Новый запрос за пределами временного окна (5 минут спустя)
{
"request_id": "req_003",
"operation": "book_taxi",
"pickup_location": "ул. Ленина, д. 10",
"dropoff_location": "пр. Мира, д. 25",
"customer_id": "cust_001",
"timestamp": "2024-11-24T10:05:00Z"
}
Response: Новый запрос за пределами временного окна
{
"status": "success",
"booking_id": "booking_002",
"message": "Taxi successfully booked.",
"pickup_time": "2024-11-24T10:20:00Z"
}
3. Установка семафоров и ограничителей: Эти механизмы контролируют количество раз, которое одна и та же операция может быть выполнена, помогая предотвратить нежелательные изменения в системе.
Семафоры и ограничители работают как контроль за частотой выполнения операций. Это особенно важно, когда система должна избежать перегрузки. Кухня в канун Нового года — идеальный пример работы семафоров. Представьте, что на вашей кухне перед Новым годом ввели строгую систему пропусков: одновременно могут готовить не более двух человек. Если кто-то третий пытается ворваться со своими «гениальными» идеями, его заставляют ждать за дверью, пока кто-нибудь не освободит место.
Так и семафоры: они ограничивают количество запросов, которые система может обрабатывать в один момент времени. Это защитный механизм, позволяющий системе работать стабильно и предотвращающий перегрузку. Порядок на кухне и в коде обеспечен.
# Максимальное количество людей на кухне одновременно
MAX_CAPACITY = 2
# Семафор, ограничивающий количество одновременных операций (людей на кухне)
semaphore = threading.Semaphore(MAX_CAPACITY)
# Функция для имитации работы на кухне
def work_on_kitchen(person_id):
print(f"Человек {person_id} вошел на кухню.")
# Захватываем семафор, чтобы начать работу
semaphore.acquire()
# Имитация работы на кухне
print(f"Человек {person_id} работает на кухне.")
time.sleep(2) # Имитируем время работы (например, 2 секунды)
# Освобождаем семафор, чтобы другие могли работать
print(f"Человек {person_id} покинул кухню.")
semaphore.release()
# Запускаем несколько потоков, имитируя людей, желающих работать на кухне
threads = []
for i in range(5): # 5 человек пытаются попасть на кухню
t = threading.Thread(target=work_on_kitchen, args=(i+1,))
threads.append(t)
t.start()
# Ожидаем завершения всех потоков
for t in threads:
t.join()
print("Все люди завершили работу на кухне.")
Инициализация семафора: Мы создаем объект семафора semaphore с лимитом в 2, что означает, что одновременно могут работать не более двух человек (или выполнять операции).
Функция work_on_kitchen: Каждый "человек" (поток) пытается зайти на кухню. Если на кухне уже два человека, остальные будут ждать.
Метод acquire: При заходе на кухню каждый поток "захватывает" семафор, который ограничивает количество потоков (людей).
Метод release: После выполнения работы на кухне человек освобождает место, позволяя следующему потоку войти.
Запуск потоков: Мы создаем и запускаем 5 потоков, представляющих людей, которые хотят попасть на кухню.
Когда два человека готовят на кухне, остальные будут ожидать своей очереди, пока кто-то не освободит место.
Вот такой вывод будет у программы:
Человек 1 вошел на кухню.
Человек 2 вошел на кухню.
Человек 1 работает на кухне.
Человек 2 работает на кухне.
Человек 1 покинул кухню.
Человек 3 вошел на кухню.
Человек 3 работает на кухне.
Человек 2 покинул кухню.
Человек 4 вошел на кухню.
Человек 4 работает на кухне.
Человек 3 покинул кухню.
Человек 5 вошел на кухню.
Человек 5 работает на кухне.
Человек 4 покинул кухню.
Человек 5 покинул кухню.
Все люди завершили работу на кухне.
Эти методы позволяют создать условия, при которых система ведет себя идемпотентно, обеспечивая надежность и предсказуемость в обработке запросов, что критически важно во многих приложениях, особенно в финансовой сфере.
Итак, вот он мир идемпотентности — от лифтов до финансовых транзакций. Этот принцип не просто технический термин; он влияет на то, как мы взаимодействуем с технологиями каждый день. Понимание идемпотентности помогает нам видеть, почему иногда меньше действий приводит к лучшим результатам и как мы можем управлять повторными действиями, чтобы не вызывать хаос.
Мы также узнали, что даже неидемпотентные методы можно "укротить" искусственно, что делает наши системы более устойчивыми и надежными. Надеемся, что теперь, когда вы нажимаете кнопку лифта или отправляете очередной онлайн-платеж, вы будете чувствовать себя немного больше в курсе того, что происходит за кулисами цифрового мира.
В конце концов, знание — это не только сила, но и способ сделать нашу жизнь проще и удобнее.
Рада, что Вы прочитали статью до самого конца! Вопросы, комментарии и идеи — с радостью жду их ниже.
Комментарии (32)
crackcraft
20.12.2024 13:07DELETE идемпотентен
Какой эгоцентризм. Вы же не в транзакции работаете. Сосед мог напостить нового между двумя делитами.
cupraer
20.12.2024 13:07И что? По спецификации
DELETE
идемпотентен. Если ключи могут переиспользоваться,DELETE
по ключу просто противоречит спецификации. С переиспользуемыми ключами иPUT
не идемпотентен, представляете себе?crackcraft
20.12.2024 13:07Я не со спекой спорю, а с тем, как это описано в статье.
Если угодно, мой кот не понимает.
mayorovp
20.12.2024 13:07Результат окажется один и тот же независимо от того, постил сосед между делитами или нет. В этом и суть идемпотентного удаления.
crackcraft
20.12.2024 13:07Тогда всю статью переписывать надо. Потому что там утверждается, что второе применение не вызывает изменений.
mayorovp
20.12.2024 13:07Не вызывает изменений если идёт сразу после первого.
Выражаясь языком математики, f(f(x)) = f(x)
cupraer
20.12.2024 13:07Это неверное определение, неясно откуда вы его взяли. Выражаясь языком математики, `f(g(f(x))) ≡ f(x), ∀g ∈ F(x) → F(x)`
mayorovp
20.12.2024 13:07Я-то своё определение взял из учебника математики, а вы свою чушь откуда взяли?
cupraer
20.12.2024 13:07Господи, вы бы с реальностью и экспериментом как-нибудь соотносили ваши учебники.
Мы про определение в вебе? Поздравляю, по вашему определению и любой
PATCH
идемпотентен. Про математику — надо смотреть как минимум определение на афинных полугруппах (потому что непрерывных параметров в вебе не бывает, печаль).Эрудиция — прекрасная штука, но интеллект, как известно, не заменяет.
mayorovp
20.12.2024 13:07Определение в вебе соответствует математическому.
Поздравляю, по вашему определению и любой PATCH идемпотентен.
Неа, не любой. К примеру, стандартный diff для текстовых файлов неидемпотентен.
Про математику — надо смотреть как минимум определение на афинных полугруппах (потому что непрерывных параметров в вебе не бывает, печаль).
А где в формуле f(f(x)) = f(x) хотя бы намёк на непрерывный параметр?
cupraer
20.12.2024 13:07стандартный diff для текстовых файлов
Стандартный кто?
PATCH
в вебе — описан в RFC 5789. У стандартного diff, как минимум, два аргумента, он вообще из другой оперы.Вы 55 минут назад сказали глупость, и теперь извиваетесь ужом, приводя нерелевантные примеры из курсов кройки и шитья (и математики), вместо того, чтобы просто согласиться с тем, что ошиблись.
mayorovp
20.12.2024 13:07PATCH в вебе — описан в RFC 5789
Формат патча в RFC 5789 не описан, он определяется реализацией (а также Content-Type), и может быть любым. В том числе тем, что используется в утилитах diff и patch.
У стандартного diff, как минимум, два аргумента, он вообще из другой оперы.
Очевидно, я говорил не об утилите, а о формате, в котором она выводит различия. Если бы вы сосредоточились на попытках меня понять, а не оскорбить -= вы бы это поняли.
cupraer
20.12.2024 13:07Если бы вы сосредоточились на попытках меня понять, а не оскорбить
Вы себе льстите, я не пытаюсь никого никогда оскорбить, за меня природа отлично справляется.
Формат патча в RFC 5789 не описан
Очередной выверт ужа на сковородке, хотя это ж хабр, да, чего я ждал. В спецификации напрямую написано то, что
PATCH
не идемпотентен (и также написано, что его можно сделать идемпотентным, да, хотя конкретная имплементация всегда облажается потому, что полная синхронизация сервера и клиента требует таких мощностей, транзакций и отсутствия моральных ценностей, что ее можно считать пренебрежимым частным случаем). Хоть сто велосипедов нагородите поверх, спецификацию это не изменит (но людей запутает, да). Все эти етаги, нонсы, диффы — поверх патча — уничтожают сам смысл существования такового запроса.
cupraer
20.12.2024 13:07Ну и чтобы вам понятнее было. Когда я говорил «по вашему определению и любой
PATCH
идемпотентен» — мне надо было сказать «по вашему определению гигантское количество патч-запросов, которые все адекватные люди (и консорциум) назовут неидемпотентными — оказываются идемпотентными».Но я отвык от людей, отстаивающих любое свое слово любой ценой, поэтому не был готов к завороту про диффы. Мог и догадаться предвидеть, да.
cupraer
20.12.2024 13:07А где в формуле f(f(x)) = f(x) хотя бы намёк на непрерывный параметр?
Да, а вот тут погорячился я.
kuza2000
20.12.2024 13:07Про методы GET, POST, PUT, DELETE довольно странные мысли. Любой из методов можно сделать идемпотентным или не идемпотентным. Метод - это лишь вариант интерфейса.
Не так давно я работал с API банка, у которого вообще все было сделано через GET, причем параметры через url. И добавление заказов, и удаление, и запрос статуса... все-все-все :)
cupraer
20.12.2024 13:07Можно, но тут речь про спецификацию, а не про то, как её можно извратить.
kuza2000
20.12.2024 13:07Видимо, да. Но об этом остается только догадываться. Если бы я не был немного в теме, я бы не понял того, что речь о спецификации этих методов. Этого не понятно ни по названию, ни по содержанию статьи. Ну и не помешало бы разъяснение, что это лишь рекомендации, которые соблюдаются далеко не всегда. Я бы даже сказал, что редко соблюдаются...
suslovas
20.12.2024 13:07Важная часть, которую надо бы вынести большими буквами для новичков в начало статьи - методы PUT и DELETE ДОЛЖНЫ быть идемпотентный в соответствии с RFC, но в реальной жизни всегда проверяйте, что нашкодили программисты, потому что никто этого не гарантирует. По сути это все го лишь слова для разграничения разных методов, а что они делают зависит от кода, и GET с POST могут использоваться для удаления записей.
И, кстати, да, по RFC идемпотентными являются в явном виде только PUT и DELETE, GET не обязан быть таковым.
mayorovp
20.12.2024 13:07Метод без побочных эффектов всегда идемпотентен.
cupraer
20.12.2024 13:07Неа, не любой [
PATCH
идемпотентен]. К примеру, стандартный diff для текстовых файлов неидемпотентен.ваши слова?
Метод без побочных эффектов всегда идемпотентен.
тоже ваши?
Простейший силлогизм:
diff
имеет побочные эффекты. Внимание, вопрос: какие именно?mayorovp
20.12.2024 13:07Применение патча формата diff к файлу, очевидно, меняет этот самый файл. Это и есть побочный эффект с точки зрения стандарта HTTP.
cupraer
20.12.2024 13:07Изменение сущности на которую указывает идентификатор ресурса при вызове небезопасного метода — побочный эффект с точки зрения стандарта HTTP?
Я сдаюсь. Искренне завидую, если вам удается зарабатывать деньги не астрологией и не финансовыми махинациями.
mayorovp
20.12.2024 13:07А что не так-то? Основной результат запроса - это ответ сервера. Всё остальное - побочные эффекты.
И, если что, "метод без побочных эффектов всегда идемпотентен" написано прямо в стандарте:
A sequence that never has side effects is idempotent, by definition
-- https://datatracker.ietf.org/doc/html/rfc2616#section-9.1.2(одиночный запрос является тривиальной разновидностью последовательности запросов, если вы решите ещё и тут придраться)
cupraer
20.12.2024 13:07О, пошло в ход вырывание слов из контекста. Полная цитата, а не те три слова, которые вам выгодны, звучит так:
A sequence that never has side effects is idempotent, by definition (provided that no concurrent operations are being executed on the same set of resources).
Когда для человека веб — однопоточная неконкурентная среда — и не такие аберрации сознания, конечно, происходят. На всякий случай уточню: я понял, что вы имеете в виду одиночный запрос (по определению неконкурентный), и что для вас
Основной результат запроса - это ответ сервера. Всё остальное - побочные эффекты.
Попробую в последний (клянусь) раз: запрос, который по идентификатору ресурса меняет значение числового поля этого ресурса на модуль его значения. Функция взятия модуля — идемпотентна (в вашей этой математике, если я правильно помню). Условию `f(f(x)) ≡ f(x)` удовлетворяет. А запрос, гад, неидемпотентен. Потому что если между двумя такими патчами прилетит запрос, меняющий это значение на его квадратный корень, — результаты окажутся разными.
Ссылку на то, что изменение ресурса по идентификатору не является по спецификации сайд-эффектом мне искать лень, да и вряд ли ее модно вообще найти, настолько это всем очевидно.
Теперь сходите перечитайте мой первый комментарий, про который вы вежливо (и абсолютно неверно) сказали «чушь», и поблагодарите за разъяснения, да вот хотя бы за то, что я потратил чуть не час, разжевывая прописные истины человеку, который не желает (не умеет?) слушать и понимать очевидные подавляющему большинству вещи.
Могу инвайт выслать — сможете мне еще раз поднасрать в карму с другого аккаунта.
koreychenko
20.12.2024 13:07А правильный ответ: идемпотентность зависит от того какими кривыми руками спроектировано АПИ. Я так понимаю тут речь про канонический REST. В реале довольно часто встречается следующее: [POST] "/object-type/:id" для обновления объекта, а вот если вызвать без параметра в урле, то будет создан новый объект.
cupraer
Эх, побольше бы таких текстов, чтобы у публики на брейнстормах не было лиц суррикатов, когда произносишь слово «idempotency» вслух.
Одно замечание:
Это
PATCH
, а неPUT
, и он не идемпотентен (и не безопасен). Если для формирования «образа» кроме футболки я надел на себя что-то еще — тоPUT
должен принести замену всему, что на мне надето. Потому что если пока я развлекаюсь с мнимой идемпотентностью смены футболки, с меня стащат штаны — образ после второй смены футболки будет сильно отличаться. В общем,PUT
— это тот жеPOST
, только идемпотентный. Он обязан принести с собой слепок всего объекта, а если он приносит только некоторые части (футболку) — этоPATCH
.mayorovp
При желании нет никаких проблем сделать PATCH идемпотентным, нужно лишь подобрать соответствующий формат дельты.
cupraer
Нет, конечно. Вы не сможете придумать такой формат дельты, который учтет все вызванные извне изменения, произошедшие с объектом между двумя вашими вызовами. Или это будет дельта, изоморфная всему объекту, что фактически означает «looks like
PATCH
, walks likePATCH
, quacks likePATCH
— let’s call itPUT
».mayorovp
Почему же?
Если говорить про json api, и оставить за скобками массивы (там и правда есть сложности), то достаточно выкинуть из схемы все неизменяемые и вычисляемые поля, а остальные сделать необязательными.
Да, подобная схема не позволит выражать изменения вида "удалил одну букву из значения некоторого свойства", но я не представляю кому вообще нужны такие подробные изменения.
cupraer
Я ничего не понял, но, судя по всему, эти ваши дельты вызваны недостаточным пониманием того, что такое «идемпотентная операция над объектом со свойствами в IT», как стало ясно из комментария ниже.
mayorovp
Интересно получается, ничего не поняли вы, а недостаток понимания - почему-то у меня...
cupraer
Да я просто на словах «json api» перестал читать, потому что оно тут вообще не пришей кобыле хвост.