Пишем полноценное веб-приложение. Часть 1 - Web API
Введение
Веб-разработка - это непрерывно развивающаяся сфера, которая стала неотъемлемой частью нашего повседневного опыта.
В этой статье мы рассмотрим ключевые аспекты разработки веб-приложений, включая этапы процесса, инструменты и лучшие практики.
Откройте для себя, как создать эффективное и мощное веб-приложение, а также узнайте о последних тенденциях в этой захватывающей области. Приготовьтесь начать свой путь в мире веб-разработки.
Стек
При разработке в этой части будем использовать следующие технологии:
Что будем делать
Для примера возьмём один из моих учебных проектов, который я показываю как простой пример своим ученикам.
Это приложение для работы с фича-флагами.
Фича-флаги - это специальные переключатели, которые позволяют менять поведение приложение во время его работы.
В этой статье попробуем написать небольшое API для работы с фича-флагами.
С чего начнём
Думаю, что рассказывать о том, как создать шаблон приложения с API, не нужно. Но на всякий случай, приложу скрин, как это делается:
Получаем шаблон приложения Web API, который можно запустить и откроется Swagger (инструмент, для отладки API).
Убираем всё лишнее
Удаляем шаблонный контроллер (WeatherForecastController
) и модель (WeatherForecast
).
Контроллер в веб-приложениях - это часть программного кода, которая обрабатывает запросы от пользователей и определяет, какой ответ будет отправлен обратно. Его можно представить как посредника между пользователем и базой данных или другими компонентами приложения.
Представьте, что вы посещаете ресторан и хотите заказать блюдо. Ваше желание (запрос) передается официанту (контроллеру), который принимает заказ, передает его на кухню (обработка запроса) и возвращает вам готовое блюдо (ответ). Контроллер определяет, какой процесс должен быть выполнен в приложении на основе запроса пользователя.
Модель данных - это набор данных, который мы можем либо принимать в контроллерах, либо отдавать из них.
Пишем свой контроллер
Создадим класс в папке Controllers
, назовём его FeatureFlagsController
:
Унаследуемся от ControllerBase
, навесим атрибуты ApiController
и Route
, в котором укажем путь для всего контроллера ([controller]
будет заменён на имя класса, без слова Controller
, автоматически):
Добавляем методы для контроллера
Методы, они же endpoints, или "ручки" (на сленге разработчиков), это конкретные пути в контроллере, на которые будут приходить запросы.
Наше приложение будет позволять управлять различными сервисами, а значит нужно как-то обозначить, для како-го сервиса мы хотим изменить фича-флаг.
Разметим для этого методы, в путях которых укажем название сервиса и имя фича-флага. Также дадим возможность указывать идентификатор пользователя, для которого хотим изменить фича-флаг (если мы захотим управлять функциональностью конкретных пользователей):
Трёхзвенная архитектура
Трёхзвенная, она же трёхуровневая (и трёхслойная), архитектура - устройство приложения, разделяемое на три слоя (звена) - контроллеры, сервисы и репозитории.
С контроллерами мы уже знакомы, остаются сервисы и репозитории.
Уровень сервисов - набор классов, в которых может хранится бизнес-логика приложения. Обычно, с этого слоя идут обращения к слою с репозиториями и манипуляция данными.
Уровень репозиториев - набор классов, в которых происходит работа по получению данных. Обращение к базе данных - это сюда.
Отложенная реализация
Принцип отложенной реализации гласит - откладывайте реализацию компонентов приложения до тех пор, пока это возможно. Это значит, что мы можем, например, не реализовывать логику работы с базой данных, пока нам это действительно не понадобиться. А пока, для быстрого тестирования, мы можем обойтись локальными методами работы с данными.
Пишем сервис
Для того, чтобы не писать всю логику приложения в контроллерах, создадим класс сервиса, в котором опишем логику работы с фича-флагами.
Почему не написать всю логику прямо в контроллерах? Можно, конечно, никто не запрещает. Но лучше этого избегать и оставлять контроллерам, например, валидацию данных. Почему лучше избегать? Потому что когда приложение будет развиваться, будет тяжело переиспользовать уже написанную логику в других местах.
Наш сервис будет очень простым - по сути, это будет просто бойлерплейт, который направит нас к слою с данными. Следуя принципу отложенной реализации, мы не захотим сразу писать сервис, поэтому просто создадим интерфейс:
Добавим этот интерфейс в наш контроллер:
И уже можем прописать логику работы контроллеров:
Разметим репозиторий
Для работы сервиса, нам будет нужен также слой репозиториев. Мы, конечно же, не хотим сейчас его писать, поэтому разметим интерфейс:
Настало время действительно написать сервис
Интерфейс это, конечно, хорошо, но кто работать будет? Идём реализовывать интерфейс.
Почему у нас три метода в сервисе
Метод установки значения для фича-флага очень сильно похож на метод его создания, поэтому мы можем объединить эту логику в сервисе, чтобы потом переиспользовать её в контроллере (вот нам и пригодились сервисы).
Откладываем реализацию репозитория
Пришло время реализовать слой работы с данными. Но мы же не хотим сейчас лезть в базы данных, верно?
Поэтому отложим реализацию, и напишем что-то вроде этого.
Добавим локальное хранилище (словарик):
Реализуем получения ключа для нашего хранилища:
Регистрируем классы
После того, как мы всё сделали, осталось сходить в DI и зарегистрировать наши классы. Идем в файлик Program
и прописываем:
Запускаем
Пробуем запустить приложение и поиграться с ним в Swagger:
Заключение
В этой статье мы разработали простое приложение, которое позволяет работать с фича-флагами.
Мы не реализовали работу с базой данных (сделаем это в следующей статье), поэтому все наши данные потеряются при перезапуске приложения.
Данный проект реализую в публичном репозитории на GitHub.