Pull to refresh

Comments 6

Для сложных поисков я бы делал общий для всех сущностей endpoint /api/search, и работал бы с ним по схеме POST/GET:

  • на URL /api/search отправляем POST со сложным запросом (возможно включающем в себя тип сущности);

  • сервер сохраняет запрос в каком-то хранилище под уникальным идентификатором id;

  • сервер в качестве результата POST отправляет клиенту id;

  • клиент отправляет GET на /api/search/{id};

  • сервер получает по id параметры ранее сохраненного запроса из хранилища, выполняет его и отправляет клиенту результат этого выполнения;

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

  • "поисковой запрос" это сам отдельный ресурс

  • /api/search/ - контейнер этого ресурса

  • /api/search/{id} - URI отдельного ресурса

  • POST /api/search/ - глагол "создать ресурс"

  • GET /api/search/{id} - глагол "получить представление ресурса c идентификатором {id}".

Этот паттерн я разбирал в главе «Асинхронность и управление временем»

https://habr.com/ru/articles/732646/

Да, он вполне возможен с точки зрения архитектуры (хотя не совсем REST-way с той точки зрения, что id — черный ящик, по нему невозможно понять, что это была за операция).

Ну почему же "черный ящик". Вполне прозрачно: /container/subcontainer/susbsubcontainer/{id} - id это идентификатор ресурса внутри контейнера /container/subcontainer/susbsubcontainer/, соответственно полный path это полный идентификатор ресурса. А операция над ним (глагол) определяется по HTTP verb (кстати в английском "verb" это как раз и означает "глагол"): GET, PUT, DELETE.

В общем-то, как вы совершенно правильно написали, на REST нет какого-то официального стандарта, но, есть т.н. "REST maturity model" описанный, например в "REST in Practice" (отличная, кстати, книга) - согласно нему "все системы, по сути, REST, но некоторые более REST чем другие" :)

Я, в общем-то, адепт такого подхода, когда полный path это всегда какой-то (уникальный) ресурс (или контейнер ресурсов, впрочем, контейнер ведь это тоже частный случай ресурса), HTTP-verb это операция над ресурсом, а query string (если он есть) это какие либо "аспекты" этой операции (например, выбор того какое представление ресурса вернуть).

Только сейчас заметил комментарий ¯\_(ツ)_/¯

Этот подход, на самом деле, описывает такой чуть более REST-овый GraphQL: есть один эндпойнт, который умеет всё (только, отличие от GraphQL, с кэшированием по id). Проблемы те же:

  1. Нельзя понять, что за операция была запрошена (надо тело читать). Отсюда такой сервис сложно профилировать (какие конкретно операции «тяжёлые») и ещё сложнее поставить рейтлимитер

  2. Содержимое GET /api/search/{id}нетипизировано — невозможно узнать, что находится внутри (какие данные каких типов), пока не прочитаешь.

Неплохо было бы еще написать статью по "правильному" использованию в REST "HTTP status code". Потому что с этим повсюду совсем беда-беда. Чего только не насмотришься - видел как вообще на все что угодно возвращали "200", в случае ошибки возвращая её при этом в теле ответа, или наоборот на любую ошибку возвращали исключительно "500".

Sign up to leave a comment.

Articles