Она просто мешает именно вам. И кому-то еще, кто на Python тоже не пишет. Я одинаково люблю С и Python, не испытывая необходимости агитировать против утиной типизации.
Такой софистикой можно оправдать любой распространенный миф. У нас будут проблемы с устойчивым определением того, какой именно смысл приобрел REST. Предлагаю вам ответить на простой вопрос: RESTful API — это API, который что?
Если быть честным, этот сайт описывает все ограничения REST, только расставляет неправильные акценты. К слову, на странице Resource Naming (рекомендации по именованию URI, с которых все начинают и на них же останавливаются) честно сказано, что "This is not a REST rule or constraint, but it enhances the API." Если это не rule и не constraint, тогда что ими является? Мало кто задается такими вопросами, поэтому имеем то, что имеем.
Это примерно как сказать, что какой-то паттерн проектирования не имеет стандарта, поэтому никто не вправе ограничивать нас в его трактовке. Так любая терминология может потерять смысловую нагрузку. Почему мы вообще даем имена вещам?
Это работает аналогично HTML-формам. Например, посмотрите на HAL формы (https://rwcbook.github.io/hal-forms/). Метод указывается явно или подразумевается из relation. Ссылка или указана явно, или может сформирована клиентом при использовании URI Template. Их хардкодить не нужно.
Идеи имеют свойство развиваться и то, что было предложено в 1994 году не факт что останется актуальным в 2020.
Базис запросто может оставаться актуальным в масштабе десятилетий без значительных изменений. Парадигмы, языки программирования, шаблоны проектирования, протоколы, спецификации, API операционных систем. Язык С был языком 2017 года по версии TIOBE, хотя на тот момент ему было более сорока лет.
Во-вторых, вы не браузер разрабатываете, а веб приложение, т.е. текстовый документ, а не текстовый редактор, если брать такую аналогию.
REST предназначен для приложений с очень длительным жизненным циклом, включая веб-браузеры и весь гипертекстовый веб как таковой. Он не является применимым для большинства API (хотя многие могли бы извлечь пользу из его ограничений).
Простой пример, у меня есть клиент и несколько серверов (нод или экземпляров микросервисов), перед которыми стоит балансировщик, какую ссылку должен вернуть сервер? На балансировщик? или без ничего?
Поскольку серверная сторона контролирует ссылки, каждая ссылка может вести куда угодно. Ссылка может быть относительной и вести на тот же домен, откуда пришел ответ. Или микросервисы сами могут "перебрасывать" клиента между собой без центрального шлюза. Этот вопрос выходит за рамки REST, но в любом случае клиент ничего не знает о внутреннем устройстве сервера.
Еще вопрос, должен ли HATEOAS описывать данные, которые требуется передать, например в body?
Схематически. Например, в HTML-формах указывается информация, отвечающая за формирование ссылки и формат данных. В случае с JSON сервер может передать описание формы через JSON Schema. В целом, это достаточно сложный вопрос. Единого решения здесь нет и не предвидится.
На моей Windows 10 LTSC программа DoNotSpy не устранила регулярные вылазки системы в сеть. Особенно в играх раздражало, когда на ровном месте пинг взлетает до 300 и ты не понимаешь, что происходит. Пришлось вручную отключать "Службу оптимизации доставки" и еще несколько служб.
Совершенно верно. Филдинг указывает на это в своей диссертации.
«At no time whatsoever do the server or client software need to know or understand the meaning of a URI — they merely act as a conduit through which the creator of a resource (a human naming authority) can associate representations with the semantics identified by the URI.» https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm#sec_6_2_4
Если копнуть немного глубже, можно узнать очень много нового)
Смотрите на то, как работают браузеры. HATEOAS из-за "позднего связывания" обеспечивает свободу в долговременной перспективе, позволяя клиенту и серверу развиваться независимо. Сервер имеет возможность менять ссылки, расположение страниц, их компоновку и поведение (до некоторой степени) без необходимости пересобирать клиент, что полезно для десктопных и мобильных приложений.
Тема очень обширна и на самом деле заслуживает отдельной статьи, но я по мере своих сил перескажу суть. REST ведет свою историю еще с 1994 года, когда Рой Филдинг был привлечен к работе над HTTP/1.0 и URI, став потом основным архитектором HTTP/1.1. В то время он формализовал концепции, которые использовались при проектировании веба, и затем, в 2000 году, REST в его законченном виде стал предметом докторской диссертации Филдинга. «The name "Representational State Transfer" is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.» https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm
Акроним HATEOAS является ничем иным, как отрывком из четвертого, центрального ограничения REST — Uniform Interface: «REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.». Практически весь современный веб, каким мы его знаем, основан на этом. Браузеры работают на гипертексте — они не содержат захардкоженных ссылок, а следуют ссылкам, которые были получены из ответов сервера, руководствуясь медиа-типами и другими метаданными. Именно из-за этого ограничения REST-клиенты похожи на браузеры.
«What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period.»
— Roy Fielding (REST APIs must be hypertext-driven)
Сейчас (на само деле давно) REST является модным ярлыком, который навешивается практически на любой HTTP API, даже если авторы понятия не имеют, что это значит.
Ресурс — это ключевая абстракция, на которой концентрируется протокол HTTP.
Природа которой не ограничена.
Транспорт: всегда HTTP. REST полностью построен на основе HTTP.
Хотя REST является формализацией концепций, заложенных в основу веба, использование HTTP не является ни достаточным, ни обязательным условием для REST.
PUT: обновить существующий ресурс
Семантически, PUT предназначен для полной замены, а не просто для обновления. Частичный PUT нарушает спецификацию HTTP. Можно смотреть на PUT как на эквивалент операции присваивания, этим, к слову, и обусловлена его идемпотентность. Для частичных обновлений подходит или POST, или PATCH.
Да, только generator не является функцией, возвращающей генератор. У нее и return нет вовсе.
В точности как класс, который не является функцией, возвращающей объект. У конструктора и return нет. Хотя оба являются callable и возвращают объекты.
Возвращающей генератор функцией является PyGen_NewWithQualName, вызываемая _PyEval_EvalCodeWithName вместо целевой функции при наличии флага CO_GENERATOR у целевой функции.
Не имеет никакого значения, как это реализовано на уровне C API. Интерпретатор PyPy делает по-другому, и что?
В отличие от корутин, которые полностью ориентированы на кооперативную многозадачность и требуют отдельного планировщика для выполнения, генераторы по смыслу использования очень близки к итераторам. Не удивительно, что в итоге их разделили (хотя принципиально они работают одинаково). Остальную чушь я комментировать не буду, прости великодушно)
Запись generator() по здравому смыслу (с которым не дружат создатели языка) не подразумевает ничего, кроме вызова generator().
Выражение generator() подразумевает вызов функции, которая возвращает объект генератора. Для этого не нужен отдельный синтаксис, потому что generator может быть генератором, классом, методом, функцией, любым callable-объектом. Вызов zip(iterable) может вернуть как генератор, так и итератор, но итерироваться они будут одинаково.
Да, выйти из своего фрейма в вышестоящий фрейм создателя генератор не может — можно условно говорить о том, что это уже не стэк, а разрозненные фреймы с данными
Совершенно верно, только не условно, а на самом деле. Можно выполнить next(g) поочередно из двух потоков, и в каждом случае фрейм генератора будет развернут на вершине стека соответствующего потока.
Да, это правда, вызов функции-генератора не имеет ничего общего с вызовом функции. Это что-то там про "явное лучше неявного".
Вызов generator() не выполняет тело генератора подобно тому, как вызов iter(iterable) не приводит к выполнению итератора — оба лишь создают итераторы, которые затем исполняются при вызовах i.__next__(). Сначала создание контекста, потом выполнение.
Однако же, стэк создания генератора существует и остается до уничтожения генератора
Нет, вы создали замыкание. Генератор не хранит никакой стек (он у потока только один), он хранит исключительно свой стековый кадр, который удерживает внутреннее состояние генератора (в том числе замкнутые переменные). Этот кадр является "осыротевшим" в моменты между выполнением генератора. Я поясню:
Здесь get_gen отсутствует в стэке исключения, хотя она есть в стэке генератора.
Он там и не должен быть. Выражение run_gen(get_gen()) делает следующее:
g = get_gen()
run_gen(g)
Вызов get_gen() вернул объект генератора, но его тело еще не выполняется. И никакого get_gen в кадре стека генератора не существует, он вообще ничего не знает что у него "сверху" в моменты, когда он не выполняется.
def gen():
print(g.gi_frame.f_back) # <frame object at 0x7f1cd002f648>
yield 1
g = gen()
next(g)
print(g.gi_frame.f_back) # None
Она просто мешает именно вам. И кому-то еще, кто на Python тоже не пишет. Я одинаково люблю С и Python, не испытывая необходимости агитировать против утиной типизации.
И ни слова про PyPy, Cython, Numba, NumPy)
Тогда я не понимаю, о чем мы говорим.
Такой софистикой можно оправдать любой распространенный миф. У нас будут проблемы с устойчивым определением того, какой именно смысл приобрел REST. Предлагаю вам ответить на простой вопрос: RESTful API — это API, который что?
Если быть честным, этот сайт описывает все ограничения REST, только расставляет неправильные акценты. К слову, на странице Resource Naming (рекомендации по именованию URI, с которых все начинают и на них же останавливаются) честно сказано, что "This is not a REST rule or constraint, but it enhances the API." Если это не rule и не constraint, тогда что ими является? Мало кто задается такими вопросами, поэтому имеем то, что имеем.
Это примерно как сказать, что какой-то паттерн проектирования не имеет стандарта, поэтому никто не вправе ограничивать нас в его трактовке. Так любая терминология может потерять смысловую нагрузку. Почему мы вообще даем имена вещам?
Длинные фрагменты кода надо заворачивать в спойлер или выкладывать на https://gist.github.com/
Это работает аналогично HTML-формам. Например, посмотрите на HAL формы (https://rwcbook.github.io/hal-forms/). Метод указывается явно или подразумевается из relation. Ссылка или указана явно, или может сформирована клиентом при использовании URI Template. Их хардкодить не нужно.
Что такое абстрактный REST?
Базис запросто может оставаться актуальным в масштабе десятилетий без значительных изменений. Парадигмы, языки программирования, шаблоны проектирования, протоколы, спецификации, API операционных систем. Язык С был языком 2017 года по версии TIOBE, хотя на тот момент ему было более сорока лет.
REST предназначен для приложений с очень длительным жизненным циклом, включая веб-браузеры и весь гипертекстовый веб как таковой. Он не является применимым для большинства API (хотя многие могли бы извлечь пользу из его ограничений).
Поскольку серверная сторона контролирует ссылки, каждая ссылка может вести куда угодно. Ссылка может быть относительной и вести на тот же домен, откуда пришел ответ. Или микросервисы сами могут "перебрасывать" клиента между собой без центрального шлюза. Этот вопрос выходит за рамки REST, но в любом случае клиент ничего не знает о внутреннем устройстве сервера.
Схематически. Например, в HTML-формах указывается информация, отвечающая за формирование ссылки и формат данных. В случае с JSON сервер может передать описание формы через JSON Schema. В целом, это достаточно сложный вопрос. Единого решения здесь нет и не предвидится.
На моей Windows 10 LTSC программа DoNotSpy не устранила регулярные вылазки системы в сеть. Особенно в играх раздражало, когда на ровном месте пинг взлетает до 300 и ты не понимаешь, что происходит. Пришлось вручную отключать "Службу оптимизации доставки" и еще несколько служб.
Совершенно верно. Филдинг указывает на это в своей диссертации.
«At no time whatsoever do the server or client software need to know or understand the meaning of a URI — they merely act as a conduit through which the creator of a resource (a human naming authority) can associate representations with the semantics identified by the URI.»
https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm#sec_6_2_4
Если копнуть немного глубже, можно узнать очень много нового)
Смотрите на то, как работают браузеры. HATEOAS из-за "позднего связывания" обеспечивает свободу в долговременной перспективе, позволяя клиенту и серверу развиваться независимо. Сервер имеет возможность менять ссылки, расположение страниц, их компоновку и поведение (до некоторой степени) без необходимости пересобирать клиент, что полезно для десктопных и мобильных приложений.
Тема очень обширна и на самом деле заслуживает отдельной статьи, но я по мере своих сил перескажу суть. REST ведет свою историю еще с 1994 года, когда Рой Филдинг был привлечен к работе над HTTP/1.0 и URI, став потом основным архитектором HTTP/1.1. В то время он формализовал концепции, которые использовались при проектировании веба, и затем, в 2000 году, REST в его законченном виде стал предметом докторской диссертации Филдинга.
«The name "Representational State Transfer" is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.»
https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm
Акроним HATEOAS является ничем иным, как отрывком из четвертого, центрального ограничения REST — Uniform Interface: «REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.». Практически весь современный веб, каким мы его знаем, основан на этом. Браузеры работают на гипертексте — они не содержат захардкоженных ссылок, а следуют ссылкам, которые были получены из ответов сервера, руководствуясь медиа-типами и другими метаданными. Именно из-за этого ограничения REST-клиенты похожи на браузеры.
«What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period.»
— Roy Fielding (REST APIs must be hypertext-driven)
Сейчас (на само деле давно) REST является модным ярлыком, который навешивается практически на любой HTTP API, даже если авторы понятия не имеют, что это значит.
https://www.youtube.com/watch?v=w5j2KwzzB-0
https://www.youtube.com/watch?v=pspy1H6A3FM&t=17m16s
https://roy.gbiv.com/untangled/tag/rest
https://www.infoq.com/articles/web-api-rest/
https://www.infoq.com/news/2016/07/microsoft-rest-api/
https://github.com/Microsoft/api-guidelines/pull/29
https://tyk.io/rest-never-crud/
https://stackoverflow.com/questions/19884295/soap-vs-rest-differences/19884975#19884975
https://twitter.com/fielding/status/1052976631374000128
Природа которой не ограничена.
Хотя REST является формализацией концепций, заложенных в основу веба, использование HTTP не является ни достаточным, ни обязательным условием для REST.
Семантически, PUT предназначен для полной замены, а не просто для обновления. Частичный PUT нарушает спецификацию HTTP. Можно смотреть на PUT как на эквивалент операции присваивания, этим, к слову, и обусловлена его идемпотентность. Для частичных обновлений подходит или POST, или PATCH.
HATEOAS является обязательной частью REST с самого начала. Ваш браузер работает на этом принципе.
В точности как класс, который не является функцией, возвращающей объект. У конструктора и return нет. Хотя оба являются
callable
и возвращают объекты.Не имеет никакого значения, как это реализовано на уровне C API. Интерпретатор PyPy делает по-другому, и что?
В отличие от корутин, которые полностью ориентированы на кооперативную многозадачность и требуют отдельного планировщика для выполнения, генераторы по смыслу использования очень близки к итераторам. Не удивительно, что в итоге их разделили (хотя принципиально они работают одинаково). Остальную чушь я комментировать не буду, прости великодушно)
Выражение
generator()
подразумевает вызов функции, которая возвращает объект генератора. Для этого не нужен отдельный синтаксис, потому чтоgenerator
может быть генератором, классом, методом, функцией, любым callable-объектом. Вызовzip(iterable)
может вернуть как генератор, так и итератор, но итерироваться они будут одинаково.Совершенно верно, только не условно, а на самом деле. Можно выполнить
next(g)
поочередно из двух потоков, и в каждом случае фрейм генератора будет развернут на вершине стека соответствующего потока.Вызов
generator()
не выполняет тело генератора подобно тому, как вызовiter(iterable)
не приводит к выполнению итератора — оба лишь создают итераторы, которые затем исполняются при вызовахi.__next__()
. Сначала создание контекста, потом выполнение.Нет, вы создали замыкание. Генератор не хранит никакой стек (он у потока только один), он хранит исключительно свой стековый кадр, который удерживает внутреннее состояние генератора (в том числе замкнутые переменные). Этот кадр является "осыротевшим" в моменты между выполнением генератора. Я поясню:
Кадр стека генератора становится частью "родительского" стека только в моменты выполнения генератора (вызовы
next(g)
).Он там и не должен быть. Выражение
run_gen(get_gen())
делает следующее:Вызов
get_gen()
вернул объект генератора, но его тело еще не выполняется. И никакогоget_gen
в кадре стека генератора не существует, он вообще ничего не знает что у него "сверху" в моменты, когда он не выполняется.