Какой из этих подходов соответствует стандартам RESTful? - PullRequest
0 голосов
/ 16 апреля 2020

1) Front-end сделает вызов GET, чтобы проверить, существует ли пользователь уже. После этой проверки, если пользователь не существует, внешний интерфейс будет выполнять вызов POST для создания пользователя.

2) Внешний интерфейс сразу же сделает вызов POST, а внутренний выполнит проверьте существование пользователя и, если этот пользователь существует, то верните детали во внешний интерфейс. Если пользователь не существует, создайте запись и верните ее обратно с подробностями во внешний интерфейс.

Какой из них является лучшим подходом в соответствии со стандартами?

Ответы [ 4 ]

0 голосов
/ 16 апреля 2020

Начнем с того, что не существует такого понятия, как «стандарт RESTful» или «URL RESTful / URI / IRI». Рой Филдинг определил архитектурный стиль, который он назвал «REpresentational State Transfer» или REST вкратце. По словам Роберта C. «Дядя Боб» Мартин: архитектура имеет намерение , и цель архитектуры REST - это сильное отделение клиентов от серверных реализаций, чтобы позволить последнему свободно развиваться в будущем, подобно браузерам и серверам, где браузер не нужно обновляться, когда сервер внезапно меняет свою структуру URI или макет страницы. Таким образом, REST вводит пару ограничений, которые при последовательном соблюдении уменьшат вероятность соединения и позволят извлечь выгоду из обещаний, которые REST пытается предоставить.

В большинстве случаев связь в архитектуре REST построена вокруг HTTP, хотя REST не ограничивается HTTP в частности. Сам HTTP также является просто распределенной системой управления документами, прикладной областью которой является передача документов через Интернет . Таким образом, по сути, HTTP просто отвечает за перенос одного документа с одного компьютера на другой. Управление документами может вызывать побочные эффекты, которые приводят к определенной обработке этих документов, что может дополнительно запускать некоторые бизнес-правила, выполняемые на серверах.

Все взаимодействие между клиентами и серверами основано на предпосылке, что Сервер должен обучить своих клиентов всему, что им нужно знать, чтобы сделать осознанный выбор, какие действия выполнять дальше. В Интернете мы так привыкли получать ссылки и формы в наших браузерах, что это уже кажется естественным. Тип HTML media определяет семантику, т.е. формы или ссылки, так что браузер, который находит такую ​​разметку, может отобразить страницу с этой информацией и представить ее пользователю. Исходя из возможности определенных элементов, клиент (пользователь) теперь руководствуется процессом дальнейшего поиска, добавления новых, изменения или удаления существующих данных. Элемент формы обучает клиента нескольким вещам одновременно. Клиент узнает не только, какой тип данных ожидает сервер, но также и URI, куда отправлять данные, формат представления, который сервер хотел бы получить, а также операцию HTTP, используемую при отправке полезной нагрузки на сервер. Здесь никакой внешней документации действительно не требуется, за исключением возможных подсказок пользователя о том, какие определенные поля ввода могут express (поле CCV на странице оплаты кредитной картой или некоторые технические сокращения, ...).

Здесь клиент и сервер мультимедийного типа являются ключевой частью всей обработки. Тип носителя, такой как application/html, определяет синтаксис и семантику, используемые в документе, и позволяет приложению обрабатывать такой документ дальше. Важно знать, что ресурс не имеет конкретного типа как таковой, но формат представления должен быть согласован между клиентом и сервером. То есть, если вы возьмете страницу с информацией об изготовителях автомобилей конкретной модели, было бы легко предположить, что такой URI, как http://some-vendor/cars/2019/some-brand/model, может возвращать сведения об этой конкретной модели автомобиля. Хотя сам URI является просто указателем на ресурс, который может возвращать такие данные или какую-то совершенно другую дату, такую ​​как изображение женщины, которая позирует перед какой-то машиной или что-то совершенно другое. Важной частью здесь является то, что не следует полагаться на то, что URI что-либо заявляет о своем контенте.

Обмен данными через application/json, однако, не подходит для архитектуры REST. Хотя обычный JSON определяет общий синтаксис для использования, в нем отсутствует поддержка выражения семантики доступных полей. В то время как JSON Гипер-схема (application/schema+json hyper-schema) или JSON Гипертекстовый язык приложений (HAL) (application/hal+json) добавляет поддержку ссылок и отношений ссылок, они все еще не может express какие данные вы действительно обрабатываете. Посредством использования определенных медиа-профилей semanti c уточнение может быть добавлено к универсальному c медиа-типу. Т.е. application/hal+json;profile=http://schema.org/Car может использоваться для указания того, что данные соответствуют семантике определения автомобиля, как определено schema.org. Затем обработчик этого документа может найти поддерживаемые поля, которые schema.org имеет для этого конкретного типа, и соответствующим образом проверить.

Опираясь на согласование типа содержимого, вы предотвратите прямую связь между клиентами и серверами, но вместо этого введете прямую связь каждого заинтересованного лица в соответствующий формат медиа-типа. Однако, поскольку обе стороны согласовывают формат представления для обмена полезной нагрузкой, обе стороны должны иметь возможность обрабатывать данные и, таким образом, уменьшать проблемы взаимодействия.

В большом количестве вопросов здесь, в SO, люди ищут способы улучшить свои дизайн с точки зрения производительности и большое количество пользователей рекомендуют сократить количество взаимодействий до минимума, в лучшем случае упаковав все в один запрос. Тем не менее, HTTP менее чем идеален при выполнении пакетных операций . Поэтому я почему-то не согласен с такой рекомендацией как таковой, поскольку она обходит очень важный аспект всей цепочки взаимодействия, который активно используется в Интернете: кэширование. Кэширование действительно эффективно, когда одни и те же данные запрашиваются снова и снова и данные меняются не часто. Т.е. детали машины могут меняться не так часто, поэтому пренебрежение кэшированием и повторное получение данных может быть пустой тратой ресурсов сервера, если эти же данные были получены всего за минуту go. Кэш автоматически лишит законной силы любое сохраненное представление для данного ключа кэша (= URI, включая параметры запроса), если небезопасная операция выполняется на запрашиваемом ресурсе или если значение свежести этого URI в кэше старше определенного порогового значения определено в заголовке Cache-Control. Таким образом, эмпирическое правило должно состоять в том, чтобы максимально использовать кэширование.

Что касается вашего актуального вопроса: эмпирическое правило здесь всегда должно заключаться в том, что бэкэнд будет проверять входные данные перед выполнением его задача. В случае вашего пользовательского примера, он должен проверить, существует ли пользователь, прежде чем создавать нового. Обычно пользователь хранится в БД, и он подразумевает ограничение уникального ключа для этой записи, которое срабатывает, когда вы пытаетесь добавить пользователя во второй раз. Таким образом, даже когда вы впервые проверяете, существует ли пользователь сначала с помощью операции GET, а сервер возвращает вам 404 Not Found, это не гарантирует, что в тот момент, когда запрос POST попадет на сервер, которого другой клиент не имеет создал этого пользователя в то же время. Таким образом, в 1) вы можете выполнять ненужную работу. Моя проблема в 2) заключается в том, что ваш интерфейс уже знает, чего ожидает ваш сервер. Хотя это естественно для системы с внешнего интерфейса на сервер, это каким-то образом противоречит принципам REST, так как интерфейс предполагает, что конечная точка ресурса обслуживает определенный тип и может напрямую отправлять эти данные на внутренний сервер. Никаких согласований типа контента, никакого обучения тому, что ожидает сервер ... Поэтому, с точки зрения «RESTfulness», я бы предложил, чтобы фронтенд попросил бэкэнд научить его, как нужно создавать пользователя. Бэкэнд может ответить представлением медиа-типа, которое поддерживает формы, такие как hal-form или halform , и затем отобразить это представление для динамического создания формы HTML в вашем Angular или ReactJS внешний интерфейс (или любое приложение, в котором работает ваш внешний интерфейс), который отображается для пользователя. Таким образом, вы освобождаете интерфейс от необходимости знать, что ожидает сервер, и может автоматически представлять новые или обновленные поля пользователю, не требуя изменения в интерфейсе напрямую. Если в течение разумного короткого времени необходимо создать несколько пользователей, представление формы можно повторно использовать из кэша, что позволит избежать дальнейших запросов, отправляемых на сервер. Конечно, фактический запрос на создание должен быть отправлен на сервер.

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

0 голосов
/ 16 апреля 2020

То, о чем вы говорите, называется операцией upsert .

Сам REST, насколько я знаю, на самом деле не говорит об этом. Это действительно сводится к вопросу:

Нужно ли клиенту знать , если операция сделала INSERT или только что вернула уже существующего пользователя?

Также: Что делать вы хотите сделать, если пользователь, которого клиент отправляет на конечную точку POST, отличается от того, который уже существует в базе данных?

Related: В REST POST или PUT лучше всего подходит для операции upsert ?

Здесь нет объективного ответа. Это зависит от требований вашего клиента и от того, как вы хотите, чтобы ваш API выглядел.

0 голосов
/ 16 апреля 2020

Как правило, вам нужно отправлять как можно меньше запросов, не теряя при этом качества ваших функций.

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

Я не знаю ни о каких стандартах, но, если вы отправите отдельный запрос, ваша прибыль будет незначительной при отправке формы. Однако, если вы хотите, чтобы некоторая проверка на стороне сервера происходила не только при отправке, но и при потере фокуса элемента, вам нужно будет отправлять запросы на проверку на стороне сервера при потере фокуса элемента. Тем не менее, вы должны отправлять такой запрос только в том случае, если со стороны клиента значение является правильным. Итак, сначала вы выполняете проверку на стороне клиента, а затем отправляете запрос на сервер.

Если вы находитесь на отправке формы, я настоятельно рекомендую отправлять один запрос на сервер, а не отправлять отдельные запросы на сервер. Однако на стороне проверки элементов формы при потере фокуса, если вы хотите сообщить своим пользователям о проблемах на этом этапе, вы можете отправлять запросы на проверку на стороне сервера, если значение проходит проверку на стороне клиента.

0 голосов
/ 16 апреля 2020

Поскольку ваш вопрос помечен с производительностью:

Второй вариант, когда вы отправили только вызов POST, будет немного быстрее, если регистрация действительна. Когда он недействителен (имя пользователя уже занято), у вас будут небольшие накладные расходы, поскольку вы отправляете данные, которые вам на самом деле не нужны.

Проблема в следующем: чего вы хотите достичь? Если вы хотите отобразить «имя пользователя уже занято» в поле ввода имени пользователя, вам нужно будет использовать запрос GET.

Если вы просто хотите показать его с дополнительной (серверной) проверкой, вы должны принять вызов POST.

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

...