Как разделить части взаимодействия API и создать более надежный интерфейсный код с помощью Vue.Js.
Резюме статьи
- Преимущества принципов ООП
- Типичное взаимодействие API компонентов Vue
- Как разделить проблемы и сделать общение более надежным
- Коммуникационный поток
- Выводы и обсуждение
Принципы ООП помогают сделать ваш код чище и проще для повторного использования
Я большой поклонник и пропагандист принципов объектно-ориентированного программирования (ООП). Они используются уже несколько десятилетий и уже доказали свою полезность. Конечно, использование шаблонов проектирования и некоторых конструкций может показаться немного нелогичным. Может показаться, что создается слишком много классов, особенно на ранней стадии разработки. Но потерпите, я объясню, почему оно того стоит.
Без принципов ООП код будет похож на машину Гомера. Многие части склеены вместе без хорошей общей концепции. Кроме того, плохой код чрезвычайно сложно расширить без нарушения других частей.
Одно из самых важных правил в ООП - разделение проблем (SoC). Просто классы и методы не должны делать слишком много. В противном случае их будет сложно исправить, отладить и расширить. Одна функциональность может быть привязана к другой, что затрудняет обновление.
Типичное взаимодействие компонентов VueJs
В Интернете доступно множество компонентов для VueJ. Или даже целые библиотеки компонентов, делающие этот фреймворк прекрасным инструментом для работы. Мне он нравится даже больше, чем Angular и определенно больше, чем React (извините, Facebook :)).
Однако компоненты Vue обычно выполняют слишком много бизнес-логики. В нашем коде мы обычно оставляем Vue для обработки DOM, пользовательских вводов и событий. Любая более сложная бизнес-логика и манипуляции с данными выходят за рамки классов TypeScript.
Одна из таких задач - связь с сервером с помощью REST API. Стандартный выбор для обмена данными через API - это пакет Axios, который отлично работает. Однако я не рекомендую включать Axios-коммуникации в компонент Vue. Ему здесь просто не место. Компонент сделает слишком много.
Что ж, если у вас есть простая задача, установка Axios в ваши компоненты будет работать нормально. К сожалению, большинство компонентов, доступных в Интернете, действительно это делают. И каждый из них использует свой стиль обработки вызовов API. Это затрудняет использование таких компонентов, например, если вы используете более надежный формат данных вашего API. В нашем проекте мы используем такую форму JSON:
{ head : { ... e.g. language, hashes, userId etc }, body : { ... api data } }
Внезапно почти ни один загруженный компонент не может обрабатывать этот тип структуры данных. И нет, мы не будем обновлять наш API только для того, чтобы соответствовать сторонним компонентам.
Включение Axios в компоненты Vue заставляет вас решать одну и ту же задачу снова и снова.
Общение не супер-простое. Вы должны позаботиться об отправке данных, ответе с сервера и, конечно же, об исключениях. Каждый звонок должен иметь дело с одним и тем же. Так почему бы не разделить общение полностью? Еще одно правило ООП, которому следует следовать: СУХОЙ - не повторяйся!
VueJs и подход ООП
Я объяснил подход ООП, который мы используем для нашего кода, в этой статье, которую я рекомендую прочитать, прежде чем вы продолжите.
Типичный пример взаимодействия API от компонента Vue может выглядеть следующим образом. Он должен иметь дело со всем, что необходимо для связи, плюс очень часто URL-адрес сервера также жестко запрограммирован там. Плотная связь всегда будет причинять боль в очень близком будущем.
created() { axios.get('https://myweb.com/posts') .then(response => { this.posts = response.data }) .catch(e => { // ... handle errors }) }
Наш подход состоит в том, чтобы полностью отделить коммуникацию от компонентов Vue. Вот пример. Предположим, мы хотим получить всех пользователей. Наш Пользовательский компонент даже не вызывает API сам по себе. Он просит класс брокера предоставить данные. Брокер - это класс, который специфичен для каждого компонента или типа данных, таких как пользователи, сообщения и т. Д. Он знает, какой URL-адрес API следует запрашивать для каждой операции (создание, чтение, обновление, удаление).
created () { this.usersBroker = this.app.resolve('UsersBroker'); this.getUsers(); } methods: { getUsers : async function (params = {}) { try { let data = await this.usersBroker.getUsers(params); this.users = this.userApiMapper.mapApiDataToModelsArray(data.data); } catch (serverExceptions) { this.serverExceptions = this.exceptionHandler.handleException(serverExceptions); } }, }
Этот компонент Vue не знает, как данные API принимаются от сервера. Зачем это нужно? Помните SoC? Компоненту Users нужны только данные, вот и все. UserApiMapper преобразует необработанные данные (массивы) в классы типа User (User.ts).
Давайте посмотрим на класс UsersBroker . На самом деле это класс TypeScript, который наш контейнер внедрения зависимостей предоставляет нам в функции create ().
export class UsersBroker{ private _brokerCore : BrokerCore; constructor (brokerCore : BrokerCore) { this._brokerCore = brokerCore; } public async getUsers (data : any) { try { return await this._brokerCore.apiGet('admin/users', data); } catch (exception) { throw (this._brokerCore.processExceptions(exception)); } } }
UsersBroker знает, какой URL-адрес нам нужно вызвать для запроса getUsers (GET: https://ourweb.com/api/admin/users) . Обратите внимание, что имя сервера не определено в этом коде. Почему? Потому что мы хотим установить ссылку на сервер только один раз в файле .env. Когда мы перемещаем код с локального сервера на сцену или в производство, мы хотим изменить имя сервера только в одном месте.
У класса BrokerCore есть следующие обязанности:
- Передает вызовы API-коммуникатору
- Подготавливает желаемую структуру данных
- Обрабатывает исключения и преобразует их в стандартные классы ServerExceptions.
BrokerCore принимает класс API-коммуникатора как зависимость. Это класс, который обрабатывает фактическое общение с помощью Axios. Давайте посмотрим:
Как видите, APICommunicator принимает данные, параметры URL и выполняет вызов API с помощью библиотеки Axios. Однако обратите внимание, что класс коммуникатора не отображает и не обрабатывает исключения. Не должно! Опять же, правило SoC! Наш коммуникатор позволяет клиентам класса регистрировать наблюдателей. Перед вызовом API и после вызова API наблюдатели уведомляются о событии. Пусть кто-нибудь другой займется отображением значка «загрузка…», предупреждением пользователя и т. Д. Коммуникатор не должен делать ничего другого, а просто общаться.
В наших проектах мы используем Laravel. Когда создается коммуникатор API, мы читаем переменную appLink, созданную кодом PHP на каждом сайте. Эта переменная берется из файла .env Laravel (единственного места, где хранится фактический веб-UR).
Коммуникационный поток
Чтобы сделать ваши веб-приложения более надежными и простыми в расширении, разделите задачи на независимые классы. Пусть каждый класс заботится только об определенных задачах.
Наши компоненты говорят специализированному брокеру получить данные. Этот специализированный брокер (например, UserBroker) знает, какой URL-адрес API следует использовать, например, для получения пользователей. UserBroker подготавливает данные, например, преобразует классы в ассоциативные массивы, а затем отправляет все в BrokerCore.
Специализированный брокер вызывает BrokerCore, который создает стандартную форму потока API. Его не волнует, что это за входящие данные. Для этого класса данные представляют собой просто ассоциативный массив.
BrokerCore вызывает класс APICommunicator, который знает, как на самом деле выполнять вызовы REST API. Он может регистрировать наблюдателей, которые получают уведомления о том, что делает коммуникатор.
Когда выполняется вызов API, мы ожидаем каких-то данных или исключения. APICommunicator не волнует, что это за данные. Он отправляет его в BrokerCore, который разделяет заголовок и тело входящих данных JSON. тело потока API отправляется специализированному брокеру (например, UserBroker), который предоставляет его компоненту Vue.
Исключения обрабатываются отдельно с помощью блоков try / catch и распространяются вверх в стандартной форме класса ServerExceptions .
Преимущества разлуки
Может быть не совсем понятно, как такое разделение помогает. Кажется, что в простой вызов участвует подавляющее количество классов. Однако представьте, что вам нужно изменить структуру потока API. Это не имеет значения для компонентов Vue, вам просто нужно исправить BrokerCore, и это не повлияет ни на что другое. Если Axios устарел по какой-либо причине, нет проблем, вы просто обновляете класс APICommunicator, а все остальное остается прежним, не зная, что что-либо изменилось на нижних уровнях.
Мы используем описанный подход во всех наших проектах, и он нам очень хорошо служит.
Выводы
ООП - это подход, дающий много преимуществ нашим проектам, особенно для расширений и обновлений. Вначале может показаться, что работы немного больше, чем необходимо, но поверьте мне, это очень быстро окупится.
Если вы любите VueJs так же сильно, как и мы, сделайте его еще более надежным с помощью разделения проблем. Пусть VueJs делает то, что умеет лучше всего - манипулирует DOM. Вынесите API-коммуникацию наружу. Если вам нравится TypeScript, мы настоятельно рекомендуем использовать его для интерфейсной ООП-разработки.
Сообщите нам свой отзыв
Пожалуйста, дайте мне знать в комментариях, что вы думаете. Связь API доставляет вам проблемы, поскольку каждый компонент делает это сам по себе? Вам нравится наш подход ООП?
дальнейшее чтение
ООП для Front-end разработки
Запахи кода и как их избежать
Репозиторий Git для ООП Front-end разработки