Мы рассмотрели некоторые фреймворки и маршрутизаторы в предыдущей части: «Создание API с помощью Go - Часть 1: Выбор маршрутизатора | Фернандо Х. Бандейра | Апрель 2021 г. | Середина"

Теперь, когда мы выбрали наш маршрутизатор, мы можем приступить к созданию наших первых конечных точек для API.

Мы будем определять структуру каталогов и создавать простой API Todo. По мере продвижения в этой серии мы будем добавлять в этот API дополнительные функции.

Код этой части доступен на Github: fernandobandeira / go-api at part-2 (github.com)

Во-первых, давайте взглянем на некоторые архитектурные стандарты:

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

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

Примечание. Существует репозиторий golang-standard / project-layout с некоторыми стандартами, используемыми сообществом. Однако это не настоящие стандарты проекта: это не стандартный макет проекта Go. · Проблема № 117 · golang-standard / project-layout (github.com)

Теперь приступим к кодированию. Мы будем следовать структуре каталогов, основанной на том, что мы обсуждали на картинке выше.

У сущностей есть собственная папка. Они составляют основу нашей области. Их также можно использовать в качестве модели БД, это вызывает некоторую связь с уровнем инфраструктуры, но все должно быть в порядке. В этом примере мы используем Gorm. Однако мы можем пересмотреть это в будущем, когда проведем сравнительный анализ и изучим способы улучшить время отклика. Как правило, с Go вы будете использовать собственные драйверы.

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

Следует иметь в виду, что если вы хотите установить для поля в базе данных значение NULL, вы должны использовать собственные типы SQL, допускающие значение NULL, или использовать этот пакет: https://github.com/guregu/null вместо строка типа, как здесь.

В Go есть много преимуществ для создания интерфейсов. Для начала вы можете разделить разные части вашего кода. Вы также можете создать имитацию для этих интерфейсов позже и использовать их для независимого тестирования вашего кода.

Здесь мы создаем папку и помещаем их внутрь. Это сконцентрирует все наши интерфейсы в одном месте. Еще одно преимущество состоит в том, что мы с меньшей вероятностью столкнемся с проблемами циклических зависимостей, особенно при тестировании.

Репозиторий будет взаимодействовать для нас с базой данных Postgres. Вы можете захотеть иметь другие базы данных или кэшировать некоторые из этих запросов с помощью Memcached или Redis. Мы можем рассмотреть это в другой части. В этом случае вы абстрагируете логику кеширования внутри репозитория, а затем реализуете адаптеры для Postgres и Memcached, вызывая их внутри этого файла.

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

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

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

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

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

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

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

Основной файл объединяет все, что мы кодировали до сих пор, включая внедрение необходимых зависимостей, создание основного маршрутизатора и прослушивание входящих запросов.

Позже мы, возможно, захотим добавить конфигурации для разных сред и оптимизировать этот файл для тестов e2e.

Прямо сейчас у нас есть такая структура папок:

  • / api / обработчики
  • / api / запросы
  • / entity
  • / интерфейсы
  • / репозитории
  • /Сервисы
  • / utils

Как мы видели в начале поста, API содержит наши точки входа, затем он вызывает нашу службу (уровень приложения), служба использует наши сущности (модели домена) и извлекает данные из нашего репозитория (инфраструктуры), Затем запрос возвращается к точке входа, где он форматируется и представляется пользователю.

Мы можем легко изменить нашу базу данных или обслуживать различные запросы и изменять маршрутизатор, не затрагивая нашу бизнес-логику (службы и сущности). Конечно, сущность также используется в качестве модели для gorm, но это не тесная связь, поскольку мы можем легко поменять ее местами с другой базой данных.

Это конец части 2. В следующей части мы рассмотрим инструментарий с ведением журнала, трассировкой, метриками и обработкой ошибок.

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

Код этой части доступен на Github: fernandobandeira / go-api at part-2 (github.com)