В один момент, в процессе создания очередного веб-сервиса, я решил собрать все свои знания и мысли по теме проектирования веб-API для обслуживания нужд клиентских приложений и изложить это в виде статьи или серии статей.
статей.
Конечно, мой опыт не абсолютен, и конструктивная критика и дополнения приветствуются.
Чтение получилось скорее философским, чем техническим, но любителям технической части будет над чем задуматься.
Сомневаюсь, что скажу в этой статье что-то принципиально новое, то, о чем вы никогда о себе не слышали, не читали и не думали.
Я просто попробую сложить всё в единую систему, прежде всего в своей голове, а это уже дорогого стоит. Тем не менее, я буду рад, если мои мысли пригодятся вам в вашей практике.
Итак, начнем.
Приближение первое: Персонажи
Клиент и сервер
Сервер в данном случае мы рассматриваем абстрактную машину в сети, которая способна принимать HTTP-запрос, обрабатывать его и возвращать правильный ответ. В контексте данной статьи его физическая сущность и внутренняя архитектура совершенно не важны, будь то студенческий ноутбук или огромный кластер промышленных серверов, разбросанных по всему миру.Точно так же нам не важно, что под капотом, кто встречает запрос у дверей, Apache или Nginx, какой неизвестный зверь, PHP, Python или Ruby его обрабатывает и формирует ответ, какое хранилище данных используется.
: Postgresql, MySQL или MongoDB. Главное, чтобы сервер соблюдал главное правило – услышать, понять и простить.
Клиентом также может быть что угодно, способное генерировать и отправлять HTTP-запрос.
До определенного момента в этой статье нас также особо не будут интересовать ни цели, которые ставит перед собой клиент при отправке этого запроса, ни то, что он будет делать с ответом.
Клиентом может быть JavaScript-скрипт, работающий в браузере, мобильное приложение, злой (или не очень) демон, работающий на сервере, или слишком мудрый холодильник (такие уже есть).
По большей части мы будем говорить о способе общения между вышеназванными двумя, таким образом, чтобы они понимали друг друга, и ни у кого из них не возникало вопросов.
Философия REST
REST (Передача представительского состояния) изначально задумывался как простой и однозначный интерфейс управления данными, который включал лишь несколько основных операций с непосредственным сетевым хранилищем (сервером): получение данных (ПОЛУЧАТЬ) , сохранение (ПОЧТА) , изменять (ПУСТАТЬ/ИСПРАВИТЬ) и удаление (УДАЛИТЬ) .Разумеется, этот список всегда сопровождался такими опциями, как обработка ошибок в запросе (правильно ли составлен запрос), ограничение доступа к данным (вдруг вам не следует этого знать) и проверка входящих данных (вдруг вы написали чушь), в в общем, все возможные проверки, которые выполняет сервер перед выполнением желания клиента.
Кроме того, REST имеет ряд архитектурных принципов, список которых можно найти в любой другой статье о REST. Пробежимся по ним вкратце, чтобы они были под рукой и не пришлось никуда идти: Независимость сервера от клиента — серверы и клиенты могут быть мгновенно заменены другими независимо друг от друга, поскольку интерфейс между ними не меняется.
Сервер не хранит состояния клиентов.
Уникальность адресов ресурсов — каждая единица данных (любой степени вложенности) имеет свой уникальный URL, который, по сути, полностью является уникальным идентификатором ресурса.
Пример: ПОЛУЧИТЕ /api/v1/users/25/имя Независимость формата хранения данных от формата передачи.
– сервер может поддерживать несколько разных форматов передачи одних и тех же данных (JSON, XML и т. д.), но хранит данные в своем внутреннем формате, независимо от того, что поддерживается.
Наличие всех необходимых метаданных в ответе — помимо самих данных сервер должен возвращать детали обработки запроса, например, сообщения об ошибках, различные свойства ресурса, необходимые для дальнейшей работы с ним, например, общее количество записей в коллекции для корректного отображения страницы.
навигация.
Позже мы рассмотрим различные типы ресурсов.
Чего нам не хватает?
Классический REST предполагает работу клиента с сервером как с плоским хранилищем данных, при этом ничего не говорится о связности и взаимозависимости данных между собой.Все это по умолчанию полностью ложится на плечи клиентского приложения.
Однако современные предметные области, для которых разрабатываются системы управления данными, будь то социальные услуги или системы онлайн-маркетинга, предполагают сложные взаимоотношения между сущностями, хранящимися в базе данных.
За поддержку этих соединений, т.е.
за целостность данных отвечает серверная сторона, тогда как клиент является лишь интерфейсом доступа к этим данным.
Так чего же нам не хватает в REST?
Вызовы функций
Необходимость выделения функций в отдельный метод управления данными продиктована тем, что вступают в силу принципы инкапсуляции методов, атомарности транзакций и обеспечения целостности данных.Чтобы не менять данные и связи между ними вручную, мы просто вызываем функцию на ресурсе (отдельном объекте или коллекции) и «скармливаем» ей необходимые параметры в качестве аргумента.
Эта операция не соответствует стандартам REST, для нее не существует специального глагола, а также способа указать имя функции, что заставляет нас, разработчиков, уходить в сторону.
Самый простой пример – авторизация пользователя.
Мы вызываем функцию POST /api/v1/auth/логин , мы передаем ему объект, содержащий в качестве аргумента учетные данные, и в ответ получаем ключ доступа.
Что происходит с данными на стороне сервера нас не волнует. Другой вариант – создание и разрыв связей между сущностями.
Например, добавление пользователя в группу.
Вызов функции группы для сущности POST /api/v1/groups/1/addUser , мы передаем объект пользователя в качестве параметра и получаем результат. Пример, конечно, надуманный, но зачастую при создании соединений возможны дополнительные операции с данными на стороне сервера.
А также Есть операции, не связанные напрямую с хранением данных как таковых, например, отправка уведомлений, подтверждение или отклонение каких-либо операций (завершение отчетного периода и т.п.
).
В одной из следующих статей я попытаюсь классифицировать эти операции и предложить варианты возможных запросов и ответов, исходя из того, с какими из них я столкнулся на практике.
Несколько операций
Часто бывает, и разработчики клиента поймут о чем я, что клиентскому приложению удобнее создавать/изменять/удалять/несколько однородных объектов одним запросом, и для каждого объекта возможен свой вердикт на стороне сервера.Здесь как минимум несколько вариантов: либо все изменения выполнены, либо они выполнены частично (для некоторых объектов), либо произошла ошибка.
Ну и стратегий тоже несколько: применять изменения только в том случае, если все удалось, или применять частично, или откатывать в случае какой-либо ошибки, а это уже приводит к полноценному механизму транзакций.
Для веб-апи, стремящегося к идеальности, хотелось бы тоже как-то занести в систему такие операции.
Попробую сделать это в одном из продолжений.
Статистические запросы, агрегаторы, форматирование данных
Часто бывает, что на основе данных, хранящихся на сервере, нам необходимо получить статистическую сводку или данные, отформатированные особым образом: например, построить график на стороне клиента.По сути, это данные, которые генерируются по требованию, более или менее «на лету» и доступны только для чтения, поэтому имеет смысл выделить их в отдельную категорию.
Одной из отличительных особенностей статистических данных, на мой взгляд, является то, что они не имеют уникального идентификатора.
Я уверен, что это не всё, с чем можно столкнуться при разработке реальных приложений, и буду рад вашим дополнениям и корректировкам.
Типы данных
Объекты
Ключевым типом данных при общении между клиентом и сервером является объект. По сути, объект представляет собой список свойств и соответствующих им значений.Мы можем отправить объект на сервер в запросе и получить результат запроса как объект. Однако объект не обязательно будет реальным объектом, хранящимся в базе данных, по крайней мере, не в той форме, в которой он был отправлен или получен.
Например, учетные данные авторизации передаются как объект, но не являются независимой сущностью.
Даже объекты, хранящиеся в базе данных, имеют тенденцию приобретать дополнительные свойства внутрисистемного характера, например, даты создания и редактирования, различные системные метки и флаги.
Свойства объекта могут быть либо собственными скалярными значениями, либо содержать связанные объекты и коллекции объектов, не входящие в состав объекта.
Некоторые свойства объекта могут быть редактируемыми, некоторые являются системными свойствами и доступны только для чтения, а некоторые могут носить статистический характер и рассчитываться на лету (например, количество лайков).
Некоторые свойства объекта могут быть скрыты в зависимости от прав пользователя.
Коллекции объектов
Когда мы говорим о коллекциях, мы имеем в виду тип ресурса сервера, который позволяет работать со списком однородных объектов, т.е.добавлять, удалять, изменять объекты и выбирать из них.
Кроме того, коллекция теоретически могла иметь свои свойства (например, максимальное количество элементов на странице) и функции (здесь я путаюсь, но такое тоже имело место).
Скалярные значения
В чистом виде скалярные значения как отдельная сущность встречались на моей памяти крайне редко.Обычно они появляются как свойства объектов или коллекций, и поэтому их можно читать или записывать.
Например, имя пользователя можно получить и изменить индивидуально.
ПОЛУЧИТЕ /api/v1/users/1/имя .
На практике эта функция редко бывает полезной, но при необходимости хотелось бы иметь ее под рукой.
Это особенно актуально для свойств коллекции, таких как количество записей (с фильтрацией или без): ПОЛУЧИТЬ /api/v1/news/count .
Файлы
Файлы есть файлы — их следует рассматривать как единую неделимую единицу.Другой вопрос, что в большинстве случаев при сохранении файла в базе данных может быть создана служебная сущность, содержащая метаданные этого файла: размер, настоящее имя, статус и т.д. Продолжение следует. Теги: ##webapi #rest #api #api
-
Asus Как Бренд Ноутбуков
19 Oct, 24 -
Курия
19 Oct, 24 -
Google Приобрел Youtube
19 Oct, 24 -
Макс Пейн 3 - Первые Скриншоты
19 Oct, 24 -
Простой Способ Залезть На Мокос
19 Oct, 24