API-интерфейсы RESTful, проектирование и архитектура серверной части, интерфейс и механизм рекомендаций (и глубокое погружение в код)

Это вторая и последняя часть моего введения в веб-приложения. Первую часть, которая включала введение, объяснения машинного обучения, высокоуровневую архитектуру, Python и базы данных, можно найти здесь: https://negoiddfelix.medium.com/introduction-to-web-applications-part-1- 3b8c95550bd6

Естественно, у меня также есть общедоступный репозиторий, где вы можете увидеть код всего, о чем мы говорили в этой серии: https://github.com/felixnego/noesis-books.

RESTful API

REST (передача репрезентативного состояния) — это не технология сама по себе, как почти все остальное, проанализированное в настоящей статье, а архитектурный шаблон программного обеспечения. Он включает в себя набор соглашений о том, как должен работать API.
Прежде всего, это то, что извлечение данных происходит путем доступа к определенному URL-адресу, предоставляемому API. Этот процесс представляет запрос конечной точки. Запрос выполняется через HTTP, а конечной точкой является ранее упомянутый URL-адрес. Последний должен иметь определенную структуру, и это представляет собой еще один набор соглашений REST:

В приведенном выше примере часть, подчеркнутая красным, «https://localhost:5001», представляет собой корневую конечную точку, а часть, подчеркнутая синим цветом, называется путем. Путь определяет, к какому конкретному ресурсу пытается получить доступ клиент, и он привязан к определенному методу/функции в бэкэнде. Чтобы понять, какие пути открыты и что из них можно получить, следует обратиться к документации по API.

Пути могут содержать переменные и/или параметры запроса, помогающие получить доступ к определенным ресурсам. В нашем примере, хотя и нельзя сказать, просто взглянув на него, «122» на самом деле является переменной. Они специально отмечены в документации, как правило, перед ними ставится двоеточие («/api/reports/topcategories/:id») или они заключаются в фигурные скобки. Параметры запроса (пример справа) идут в последовательности, начинающейся со знака вопроса, представлены парами ключ-значение (параметр=значение) и, при необходимости, разделяются амперсандом («&»). Как и переменные, они анализируются и передаются в логику, которую API выполняет при запросе конечной точки.

Комбинация структуры пути и методов HTTP, используемых для их доступа, является большой частью парадигмы RESTful. В таблице ниже описаны наиболее распространенные операции CRUD, а также соглашения RESTful для каждой из них:

Как легко увидеть, закономерности проявляются как в отношении метода, так и в отношении конечной точки. Таким образом, GET используется для чтения/извлечения данных, POST используется для создания новых данных или обновления существующих записей, а DELETE используется именно так, как следует из его названия. Когда кто-то пытается получить список сущностей или создать новый, используя разные методы, необходимая конечная точка обычно представляет собой просто косую черту, за которой следует множественное число имени сущности. Чтобы перейти к определенной записи, добавляется еще одна косая черта и ее идентификатор.

Давайте немного обратимся к тому, как два наиболее часто используемых метода, GET и POST, обрабатывают передачу данных.

Как в методе GET, так и в методе POST некоторые данные отправляются от клиента к серверу, однако подход отличается. Как было показано ранее, в запросе GET могут быть заполнены переменные, которые сервер будет анализировать и использовать или запрашивать параметры прямо в URL-адресе. Этот подход не рекомендуется для любых конфиденциальных или больших данных. Вот почему, например, при создании новых объектов используется POST-запрос. При таком методе данные отправляются в теле запроса, а не в URL-адресе, как показано во фрагменте выше.

Серверный API ASP.NET Core

Ни одно современное, крупное, масштабируемое приложение не может быть построено только с использованием стандартной библиотеки языка программирования. Именно здесь появляются фреймворки, облегчающие работу. Различие между библиотекой и фреймворком поначалу может быть тонким, но оно очень важно. Если коротко и псевдометафорически, библиотека — это код, который мы импортируем и используем всякий раз, когда он нам нужен. С точки зрения инверсии управления, фреймворк — это то, что использует наш код, а не наоборот. Возможно, правильнее будет сказать, что наш код адаптирует фреймворк к нашему конкретному варианту использования. Фрагменты, используемые из библиотеки, оборачиваются в пользовательский код while, а пользовательский код — в фреймворк.

ASP.NET Core — это среда веб-разработки, которая предлагает преимущества открытого исходного кода, кроссплатформенности и оптимизации производительности. Платформа .NET очень популярна и пользуется большим сообществом, в то время как язык программирования C# должен казаться очень простым для освоения разработчиками, перешедшими с Java. Он поддерживает создание нескольких различных типов веб-приложений, таких как MVC (Model View Controller), хотя для Noesis был выбран вариант веб-API.

Будучи довольно «самоуверенным» фреймворком, он создаст впечатляющую структуру каталогов и несколько строк кода, которые можно использовать для начала работы. Что касается организации этого конкретного бэкэнд-API (но в определенной степени и его внешнего клиента), была выбрана многоуровневая архитектура. Он обеспечивает столь необходимое разделение задач с некоторой степенью разделения и оказывается хорошим дополнением к внедрению зависимостей .NET Framework. В общих чертах многоуровневая архитектура изображена на схеме ниже:

Пользователь взаимодействует со слоем представления, который представляет пользовательский интерфейс. Любое действие, которое они выполняют, запускает выполнение бизнес-логики, за которую отвечает служба. Служба будет вызывать уровень репозитория для извлечения данных или управления ими по мере необходимости. Пользовательский интерфейс не выполняет бизнес-логику, и служба не обращается к базам данных напрямую.

В случае настоящего приложения пользовательский интерфейс будет представлен клиентом Angular. В нашем внутреннем API мы определяем компоненты для двух других уровней. Как и многие современные приложения, Noesis управляется данными, а это означает, что моделирование данных — хорошее начало. Наши модели определяются как классы со свойствами и без методов. Ниже приведен пример, иллюстрирующий модель Author и способ создания таблицы в базе данных:

Отношения между сущностями также определяются на уровне кода, как видно из строки 22, которая показывает реализацию отношения «многие ко многим». Своеобразная линия 11 изображает аннотацию, которую можно использовать для обеспечения согласованности и целостности данных. Однако разработчики также могут написать свою собственную проверку, используя специализированные пакеты, такие как Fluent:

Для обработки связи между базой данных MySQL и моделями C# Noesis использует ядро ​​Microsoft Entity Framework (EF). Это очень мощная ORM для платформы .NET. EF Core предоставляет множество инструментов для обработки данных, наиболее важным из которых, пожалуй, является контекст. Контекст — это специальный класс, который наследуется от DbContext и выполняет все транзакции. Можно с уверенностью сказать, что в данном случае он представляет уровень репозитория приложения. Кроме того, именно здесь можно определить ограничения или каскадное поведение для таблиц базы данных, как показано в примере ниже:

Чтобы сделать передачу полезной нагрузки между серверной частью и интерфейсом более эффективной, используется общий шаблон с использованием DTO (объектов передачи данных). Их два основных варианта использования: во-первых, серверная часть не должна отправлять объекты целиком, если достаточно только определенных полей, и, во-вторых, некоторые поля необходимо манипулировать перед отправкой как часть ответа, не желая изменять сама модель. Как уже упоминалось, поскольку шаблон очень распространен, после определения классов DTO можно использовать внешний пакет, такой как AutoMapper, который помогает преобразовывать базовые объекты в DTO и наоборот.

Также был определен сервисный уровень с четырьмя классами, обрабатывающими разные сущности. Они используют экземпляр класса контекста для взаимодействия с данными и выполнения бизнес-логики транзакций CRUD или создания отчетов. Однако классы обслуживания не отвечают полезными нагрузками напрямую интерфейсу. Это входит в обязанности контролеров. Как показано ниже, контроллер — это место, где определяются конечные точки, а также методы HTTP, которые они принимают. В случае с Noesis они не выполняют никакой бизнес-логики, хотя для небольших приложений это также в определенной степени возможно. Они отправляют это в разные службы.

Декоратор в строке 18 помогает определить общий корень «/api/books»40 для всех путей, обрабатываемых внутри этого класса. Строка 41 указывает, что функция под ней должна вызываться при выполнении HTTP-запроса GET. Поскольку в «HttpGet» не передается никакой другой параметр, он будет обрабатывать вышеупомянутый корневой путь.

Другие декораторы могут быть добавлены, чтобы обеспечить взаимодействие с конечной точкой желаемым образом. Например, «[Authorize(Roles = UserRole.Admin)]» используется для ограничения доступа только для администраторов.

Платформа может объединить все это с помощью кода, представленного в файле Startup.cs. Здесь указываются все конфигурации уровня приложения, включая, например, аутентификацию JWT (JSON Web Token). Хотя отправка данных для входа через HTTPS технически безопасна, иногда предпочтительны другие методы аутентификации и авторизации. С JWT, способом, выбранным для Noesis, после того, как клиент сделал первоначальный запрос, который был проверен сервером, последний отвечает токеном с цифровой подписью, который сохраняет клиент, поэтому серверу не нужно хранить данные. Каждый последующий запрос от клиента сопровождается токеном. Сервер должен убедиться, что токен не был подделан, и, если операция прошла успешно, он отвечает запрошенными данными.

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

Угловой интерфейс

Angular — это интерфейсный фреймворк на основе JavaScript, используемый при разработке SPA, который работает с концепцией повторно используемых компонентов, как и его основная альтернатива React. Во введении к этой статье кратко объясняется, что такое SPA и чем рендеринг на стороне клиента отличается от рендеринга на стороне сервера, а в настоящей главе мы подробно рассмотрим, как работает Angular, на примерах из того, как было построено приложение Noesis.

Есть две основные части Angular: компилятор и среда выполнения. Angular использует для разработки TypeScript, который, согласно официальному сайту, является «расширением JavaScript», предоставляющим типы для языка, превращая его в версию, более похожую на Java или C#. Фреймворк также использует многие функции ES6, такие как классы, которые на момент написания этой статьи не полностью поддерживаются во всех браузерах. Таким образом, компилятор используется для преобразования TypeScript, декораторов Angular и других функций в более простой JavaScript, понятный среде выполнения.

Angular начинает сборку («бутстрапы» в их терминологии) приложения из корневого компонента, который он находит, создает и отображает. Из-за природы SPA последующие компоненты будут частью этого корня. Не вдаваясь в слишком много технических деталей, выходящих за рамки этой статьи, отметим, что у каждого компонента есть шаблон, HTML-код, интерполированный специальным синтаксисом, подобным JavaScript, который используется для представления того, что будет отображаться в DOM (объектная модель документа). HTML-код, написанный в шаблоне, не используется напрямую при рендеринге. Angular использует некоторые специальные функции, которые анализируют шаблон и добавляют полученный HTML в DOM. Хотя это может показаться медленным и дорогим в контексте таких подходов, как виртуальный DOM React, Angular делает это только при первоначальном создании компонента, а затем использует массив под названием Logical View для внутреннего отслеживания всего отображаемого и внесения изменений в элементы. быстрее, в отличие от использования дорогих и медленных традиционных API DOM.

Помимо корня, Noesis использует 13 компонентов для выполнения ролей, ожидаемых приложением его типа, таких как список всех книг, сведения об одной конкретной записи, компонент для добавления и обновления книг, для регистрации и входа в систему. и т. д. При доступе к домашнему URL-адресу приложения пользователю предоставляется простая целевая страница, на которой он может зарегистрироваться, войти в систему или просто войти в качестве гостя. После нажатия «Enter» они перенаправляются к компоненту book-list, который выступает в качестве главного узла для приложения.
Под заголовком компонент показывает, какие три основные категории книг (по количеству записей), и для каждой из них он отображает шесть книг с самым высоким рейтингом. Затем появляется список карточек книг с соответствующей информацией, который заполняется по мере того, как пользователь прокручивает страницу до конца. Чтобы добиться эффекта бесконечной прокрутки, серверная часть использует традиционную разбивку на страницы, извлекая несколько записей за раз и запоминая, сколько нужно пропустить для следующего запроса. Во внешнем интерфейсе, как и в других элементах, мы используем Angular Material43, чтобы добавить анимацию вращающегося колеса в конец списка и заменить ее данными, как только они поступят с сервера.

При нажатии «Подробнее» пользователь перенаправляется на страницу с подробной информацией о книге, доступную с помощью другого компонента. В левой части страницы отображается панель с некоторой информацией о книге, такой как издатель, количество страниц, ISBN, год публикации и описание. Он также показывает свой текущий рейтинг с десятичными и желтыми звездами, его автора и категории, к которым он принадлежит. На последних отображаются использованные материальные чипы. Ниже зарегистрированный пользователь может оставить рейтинг, и если он является администратором, он может увидеть поле «Суперсилы администратора» с двумя специальными кнопками, одна для редактирования сведений о записи, а другая для ее полного удаления.

С правой стороны у нас есть изображение с обложкой книги, взятое с Amazon, а под ним зарегистрированные пользователи могут вводить и сохранять персонализированные заметки для книги, такие как любимые цитаты, комментарии и так далее. Заметки могут просматриваться только вошедшим в систему пользователем и создаются с помощью CSS и анимации, чтобы придать им вид офисных стикеров, они отображаются в разных цветах, увеличиваются и немного меняют положение при наведении. Их также можно удалить или отредактировать, не выходя из этого представления:

Наконец, в этом представлении также находятся компоненты раздела комментариев, где, естественно, все комментарии, оставленные в этой книге, отображаются для всеобщего обозрения. Зарегистрированные пользователи могут участвовать в беседе, оставляя свою. Если они оставили комментарий, для него в таблице появятся две специальные кнопки, чтобы удалить или отредактировать его:

Стоит отметить, что один и тот же компонент используется как для обновления существующей книги, так и для добавления новой, так как действия очень похожи. Как упоминалось ранее, эта функция доступна только администраторам, а добавление новых книг легко доступно прямо из панели навигации. Этот компонент upsert использует всплывающее окно, которое он заполняет формой, также являющейся частью Angular Material, вместо перенаправления на другую страницу. Одна из интересных вещей здесь — реализация того, как вводятся категории и авторы. Пользователи могут искать существующие записи с фильтрацией в реальном времени по мере ввода или создавать новые записи, набирая и нажимая клавишу возврата.

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

Возможно, одним из самых привлекательных аспектов SPA и фреймворков, таких как Angular, является то, что они созданы для обнаружения изменений в приложении и повторной визуализации пользовательского интерфейса без использования обновления страницы. На низком уровне Angular переопределяет API-интерфейсы DOM прослушивателя событий по умолчанию, чтобы улучшить их функциональность. Все события браузера, запросы и другие специальные функции запускают систему обнаружения изменений, в которой также вызывается хук жизненного цикла, поскольку каждый компонент имеет связанный детектор изменений.

Компоненты — очень мощный инструмент и самая важная функция фреймворка. Они дополняются другими библиотеками, а также дополнительными слоями, которые пишут разработчики, такими как модель данных и сервисный слой. Существует также уровень развязки, очень похожий на тот, что представлен в бэкенде Noesis. Таким образом, компонент не отправляет HTTP-запросы напрямую на сервер для получения необходимых ему данных. Вместо этого он использует класс BookService и перекладывает эту ответственность на него. Angular использует объекты RxJS и Observable для достижения асинхронности при обработке запросов данных. Наблюдаемые объекты можно рассматривать как фьючерсы из других языков программирования и, в меньшей степени, как обещания в JavaScript. Помимо предоставления примера для этого, приведенный ниже фрагмент также демонстрирует (с HTTP-клиентом, который передается конструктору), что Angular также использует внедрение зависимостей. Это очень помогает при тестировании компонентов изолированно.

Одностраничные приложения никуда не денутся, и, наряду с React и Vue, Angular по-прежнему является сильным конкурентом на рынке интерфейсных фреймворков.

Совместная фильтрация, ALS и интеграция механизма рекомендаций

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

ALS (Alternating Least Squares) — это реализация совместной фильтрации, которую можно найти в библиотеке машинного обучения Apache Spark. Это важный аспект, поскольку библиотеки, обычно используемые в ML, плохо работают в распределенной среде. ALS может работать параллельно в нескольких разделах, хорошо масштабируется и считается более простым, чем альтернативы. Он также получил приз от Netflix.
Мы представим нашу рекомендательную систему как веб-API с двумя конечными точками: одну для обучения и одну для получения рекомендаций для определенного идентификатора пользователя. Для этой цели использовалась фляга. Во-первых, из-за выбора Python для этого микросервиса, так как это самый популярный язык программирования для ML и к нему проще подойти, чем к Scala или Java, к другим вариантам Apache Spark. Во-вторых, потому что, в отличие от Django, Flask гораздо более легковесный и беспристрастный. Вся точка входа для приложения составляет всего 20 строк:

В функции train_model() данные считываются из базы данных MySQL, а затем преобразуются в RDD (Resilient Distributed Dataset), представляющий собой объект особого типа, который Spark использует для выполнения распределенных вычислений. Затем модель ALS обучается на RDD и сохраняется локально. При вызове функции get_recommendations() она загружает модель, передает в качестве входных данных идентификатор пользователя и возвращает список рекомендаций.

Модель будет повторно обучаться каждый раз, когда запрашивается конечная точка /train. Клиент Angular будет достигать этой конечной точки каждый раз, когда пользователь добавляет новую оценку любой книге. Это поможет обеспечить максимальную релевантность предоставляемых рекомендаций. Конечно, в текущую версию Noesis добавлены случайные данные, когда дело доходит до оценок пользователей. Однако даже в этом случае после того, как определенный пользователь просмотрит пару книг, рекомендации меняются в лучшую сторону.

Выводы

Из тенденций на момент написания этой статьи ясно, что веб-приложения будут по-прежнему оставаться среди популярных вариантов программных решений. Появление таких технологий, как React Native или Progressive Web Apps, похоже, подтверждает это утверждение. В предыдущей главе мы видели, как легко интегрировать микросервис машинного обучения в веб-приложение. Команде разработчиков не обязательно нужна помощь специалиста по данным для оптимизации гиперпараметров, чтобы воспользоваться преимуществами машинного обучения. Понимания высокого уровня более чем достаточно для обучения модели, так как тяжелая работа ляжет на выбранные библиотеки. Поскольку все больше и больше приложений становятся управляемыми данными, а возможности для взаимодействия пользователей становятся больше, чем раньше, хранение данных и проектирование данных становятся рутинными аспектами архитектуры программного обеспечения для средних и крупных приложений, а это означает, что возможность получить большую ценность с помощью ML- В эпоху «больших данных» объем аналитических данных вырос в геометрической прогрессии.

Noesis — это всего лишь довольно простой пример того, как портал от энтузиастов книг может улучшить пользовательский опыт и удержание, а также может предоставить ценную информацию для бизнеса за счет интеграции службы рекомендаций. Алгоритм, используемый в этой статье, представляет собой упрощенную версию того, как таким платформам, как YouTube и Netflix, удалось добиться такого роста за счет предоставления персонализированных предложений. Эпоха приложений с поддержкой ИИ не наступает. Это уже здесь.

Дальнейшее чтение

«Краткое введение в контролируемое обучение». Эйдан Уилсон. Средняя корпорация. 29 сентября 2019 г. (https://towardsdatascience.com/a-brief-introduction-to-supervised-learning-54a3e3932590).

«Обзор различных типов баз данных: реляционные и нереляционные». Кейт Д. Фут. 21 декабря 2016 г. (https://www.dataversity.net/review-pros-cons- Different-Databases-Relational-versus-non-Relational/#)

«Обнаружение угловых изменений — как это действительно работает?» Угловой университет. 24 апреля 2020 г. (https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/)

«Создание службы рекомендаций фильмов с помощью Apache Spark и Flask — часть 1». Хосе А. Дианес. Кодементор. 8 июля 2015 года.

«Введение в обучение с подкреплением». Анубхав Сингх. DataCamp Inc. 30 ноября 2018 г. (https://www.datacamp.com/community/tutorials/introduction-reinforcement-learning)

«Прототип системы рекомендаций, шаг за шагом, часть 2: Факторизация матрицы чередующихся наименьших квадратов (ALS) в совместной фильтрации». Кевин Ляо. Середина. 17 ноября 2018 г. (https://towardsdatascience.com/prototyping-a-recommender-system-step-by-step-part-2-alternating-least-square-als-matrix-4a76c58714a1)

«Реляционная и нереляционная базы данных: плюсы и минусы». Дэвид Паулан. ООО «АлоаЛабс». (https://aloa.co/blog/relational-vs-non-relational-database-pros-cons).

«Реляционные и нереляционные базы данных: какая из них подходит вам?» Жаклин Хоман. ООО "Плюралайт". 5 апреля 2014 г. (https://www.pluralsight.com/blog/software-development/relational-non-relational-databases)

«Одностраничное приложение против многостраничного приложения». Scandt Ltd. 16 мая 2019 г. (https://scand.com/company/blog/single-page-application-vs-multi-page-application/).

«Неконтролируемое обучение». Маргарет Роуз. Техтаргет. (https://searchenterpriseai.techtarget.com/definition/unsupervised-learning)

«Неконтролируемое машинное обучение: что это такое, алгоритмы, пример». Гуру 99. (https://www.guru99.com/unsupervised-machine-learning.html)

«Что такое база данных ключ-значение?». Amazon Web Services, Inc. (https://aws.amazon.com/nosql/key-value/)

38

«Что такое глубокое обучение?» Джейсон Браунли. Machine Learning Mastery Pty. Ltd., 16 августа 2019 г. (https://machinelearningmastery.com/what-is-deep-learning/)

«Что такое машинное обучение?» Карен Хао. Обзор технологий Массачусетского технологического института. 17 ноября 2018 г. (https://www.technologyreview.com/2018/11/17/103781/what-is-machine-learning-we-drew-you-another-flowchart/).

«Что такое обучение с подкреплением? Полное руководство». Конрад Будек. Deepsense.ai Inc. 5 июля 2018 г. (https://deepsense.ai/what-is-reinforcement-learning-the-complete-guide/)

«Что такое контролируемое обучение и его различные типы?». Акаш Кумар. Brain4ce Education Solutions Pvt. Ltd. 26 ноября 2019 г. (https://www.edureka.co/blog/supervised-learning/#applications)

«Что такое Веб 2.0». Тим О’Райли. O’Reilly Media Inc., 30 сентября 2005 г. (https://www.oreilly.com/pub/a/web2/archive/what-is-web-20.html)

«Какой процент интернет-трафика приходится на мобильный?» Оберло. (https://www.oberlo.com/statistics/mobile-internet-traffic).

"Какая разница? Реляционные и нереляционные базы данных». Адам Уайт. Izenda Inc. 21 октября 2019 г. (https://www.izenda.com/relational-vs-non-relational-databases/)