За летними делами пропустил историческую новость: в протокол HTTP добавили новый метод! Не каждый день бывает.
Добавление свежее, июньское, RFC 10008. Статус у него — Proposed Standard, но с таким статусом множество технологий живет, это значит — в целом норм, можете уже реализовывать в своих системах. В Nginx новый метод уже поддерживается. Называется этот метод QUERY. используется он примерно так:
QUERY /products/search HTTP/1.1
Host: api.example.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
q=distributed+systems&category=books&min_year=2025&sort=relevance
То есть, это фактически официальный GET с телом.
Проблема была в чем: если вы хотите найти что-то по сложному условию и множеству параметров, можно использовать GET, но параметры поиска можно передать только в строке запроса. Тела запросам GET не положено — его можно передать, но сервер или любой промежуточный узел может это тело проигнорировать и дальше не передавать. Строка запроса обычно ограничена по длине, есть даже специальный код ответа 414 URI Too Long.
GET безопасный, идемпотентный и кэшируемый.
POST небезопасный, неидемпотентный и не кэшируется. Зато у него может быть тело большого размера.
QUERY объединяет самое лучшее: он идемпотентный, безопасный, может кэшироваться и содержать тело. Заодно не оставляет следов в логах (что там было в теле — не видно). Так что если ваши запросы были слишком специфичны — теперь для них есть специальный механизм.
В каком именно формате вы будете передавать запрос в теле, стандарт не задает, но требует, чтобы вы явно указали это в заголовке Content-Type.
Там есть всякое интересное:
application/x-www-form-urlencoded — это строка запроса из URL
application/sql — SQL-запрос (вот так, прямо через REST API)
application/jsonpath — для вытаскивания специфических данных из JSON
application/xslt+xml — то же для XML
application/graphql — запрос в формате GraphQL
application/sparql-query — запрос в формате SPARQL
и т.д.
Можно спросить у сервера, в каких форматах он готов принимать запросы (он ответит в заголовке Accept-Query).
Можно ещё добавить Accept, то есть, например, в одном эндпоинте передавать простые запросы через строку, а для сложных переходить на SQL (теоретически), и получать ответ либо в JSON, либо в CSV (если сервер умеет). Всякую интересную логику можно реализовать.
Начинают играть коды ответов, про которые никто и не помнил:
415 Unsupported Media Type — сервер не поддерживает этот формат запроса к этому ресурсу
422 Unprocessable Content — сервер поддерживает этот формат, синтаксис запроса валидный, но выполнить его невозможно (например, нет такой таблицы, к которой обращается SQL)
406 Not Acceptable — клиент запросил ответ в таком формате, который не поддерживается сервером.
Сервер может даже создать новый ресурс, содержащий результат выполнения запроса! Как явный кэш, или как снэпшот на определенное время. Вернуть ссылку на него клиенту в заголовке Content-Location, а дальше к нему уже можно делать обычный GET. Сам QUERY при этом остается безопасным — новых ресурсов при повторных вызовах создаваться не будет.
Вот такая штука. Слышали уже? Планируете использовать?