Дизайн API играет большую роль в создании приложений. Если вы не спроектируете его хорошо, вам придется столкнуться с минусами в будущем. Архитектура микросервисов позволяет большому приложению делиться на множество небольших, автономных, слабо связанных сервисов. Микросервис работает как подключаемый компонент, который мы можем изменить в любое время, не затрагивая другие сервисы в архитектуре микросервиса. Работая над микросервисной архитектурой, мы пишем много сервисов. Если мы не определим это правильно, это создаст много проблем для других пользовательских сервисов/пользователей API. Если вы не разработаете надлежащий ответ, потребительские службы не будут знать, что происходит за обращением в службу поддержки. Мы всегда пишем как минимум 3 слоя для любого заданного API, например. Контроллер, сервис, дао. Здесь мы всегда должны стремиться к четкому разделению ответственности.

  1. Конечные точки. Вокруг много дискуссий. Но мы бы увидели рекомендуемые практики для этого. Начнем с нескольких примеров
  • getEmployees
  • addEmployee
  • deleteEmployee
  • найтиEmployeeById
  • Обновить сотрудников и т. д.

С этой практикой связаны значительные проблемы. Допустим, вы пишете еще один API для клиента, поэтому в итоге вы напишете много похожих конечных точек, используя данную практику. Итак, в конце концов, ваше приложение будет иметь конечные точки. Было бы трудно поддерживать их. В конечном итоге вы создадите несколько конечных точек для одного и того же ресурса, например. сотрудник, клиент и т. д., что не требуется вообще. Конечные точки API не должны содержать никаких глаголов, действий. У нас должно быть только существительное (ресурс во множественном числе) в конечной точке. Нам не нужно выполнять действия в конечной точке, здесь доступны различные методы https (GET, POST, DELETE, PUT). Теперь, если мы будем следовать этой практике, у нас должны быть такие конечные точки:

  • ПОЛУЧИТЬ путь/сотрудников
  • УДАЛИТЬ путь/сотрудников/id
  • POST-путь/сотрудники

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

  • VALIDATION_ERROR, когда введенные данные неверны, например, несколько полей могут быть пустыми и т. д.
  • ORDER_NOT_FOUND, когда не удается найти заказ с указанной информацией.
  • ORDER_CANCELED, когда заказ был отменен.
  • REFUND_FAILED, когда возврат уже обработан.
  • INVALID_AMOUND неверная сумма
  • ТЕХНИЧЕСКАЯ_ОШИБКА

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

  • Создайте пользовательское исключение (создайте пользовательское исключение, которое принимает сообщение, код состояния в качестве входных данных) из службы на основе этих вариантов использования, например. недопустимая сумма, проверка ввода, сбой возврата и т. д., и обработайте ее в контроллере.
  • Создайте окончательный ответ API, передав информацию об исключении служебному методу ответа, который принимает код состояния, сообщение в качестве входных данных и дает окончательный ответ.
  • Избегайте создания окончательного ответа на сервисе, так как окончательный ответ API содержит сообщение об успешном выполнении, код ошибки и сообщение, которое не следует делать на уровне сервиса. Бывают случаи, когда мы вызываем разные службы из одной службы и не ожидаем ответа в таком формате. Это нарушает принцип «четкого разделения слоев». Служба не несет ответственности за получение окончательного ответа API. это то, что должно быть сделано на уровне контроллера.

3. Контроллер:Контроллер — это место, где вы сначала получаете запрос. У нас всегда должны быть классы dto, разработанные для контроллера. Никогда не смешивайте классы домена (entity/document) с контроллером, поскольку мы всегда ожидаем, что эти два класса будут вести себя по-разному. Возьмем пример

  • Класс домена (сущность/документ) может иметь много полей, но мы можем не захотеть отправлять все потребителю. Имейте классы dto с обязательными полями.
  • Есть случаи, когда нам нужно сравнить наши классы моделей. Скажем, при обновлении любого доменного объекта вы хотите записать его в историю с измененными полями. Когда вы думаете о сравнении двух объектов POJO, вы заботитесь обо всех полях, но объект домена можно сравнить, просто используя идентификаторы. Таким образом, эти классы предназначены не только для передачи информации об объекте предметной области с одного уровня на другой, существуют различия в поведении.
  • Контроллер не должен иметь никакой бизнес-логики.
  • Рекомендуется построить окончательный ответ на контроллере, так как это место, где мы должны построить окончательный ответ с заданным кодом состояния, сообщением. Уровень службы передает код состояния, сообщение в виде пользовательского исключения, которое необходимо обрабатывать на уровне контроллера.
  • Не следует вызывать несколько служб из контроллера, вместо этого должна быть новая служба, которая при необходимости вызывает несколько служб. Опять же, мы должны быть осторожны с точки зрения проектирования ex. что, если первая служба выдает исключение, дает пустой ответ и т. д. Попробуйте разработать правильный код состояния, сообщение вокруг него.
  • Не следует вызывать Dao/репозиторий из контроллера, так как это не входит в обязанности контроллера.

4. Сервис. Сервис — это место, где должна быть написана бизнес-логика вашего API.

  • Всегда старайтесь разделить методы обслуживания на маленькие методы. Опять же, если мы разделим его на частные методы, возникнут проблемы с разработкой тестовых случаев. Вы можете переместить эти частные методы в класс адаптера, иметь статические методы для достижения того же, поскольку трудно охватить все возможные варианты использования частных методов из вызова тестового примера. Иногда для тестирования всех сценариев требуется несколько больших конфигураций. Мы также можем иметь эти методы как частный пакет и хранить его в том же классе обслуживания.
  • Всегда выполняйте проверку полей ввода и выбрасывайте пользовательское исключение с кодом ошибки проверки и сообщением об ошибке, специфичным для полей. Если необходимо проверить несколько полей, переместите их за пределы службы. Иметь класс валидатора для написания проверки для всех полей. Это делает ваши сервисные методы маленькими и чистыми.
  • Допустим, есть два объекта домена A, B, и у нас есть два разных репозитория, определенных для этих двух. Есть случаи, когда нам нужно получить информацию о других объектах домена. В этом случае мы не должны вызывать методы репозитория B напрямую из метода службы A. Всегда старайтесь использовать класс обслуживания для методов репозитория, даже если он вам нужен в контроллере. Поскольку есть несколько вещей, которые мы обрабатываем на уровне службы, а не на уровне репозитория, например. транзакция, кэширование и т. д.
  • Не смешивайте два объекта/репозитория домена с одним и тем же методом обслуживания.
  • При вызове внешних служб или других служб, если мы не получаем требуемые данные, создаем пользовательское исключение с требуемым кодом состояния, сообщением об ошибке.
  • Не делайте ничего, относящегося к слою репозитория в сервисе. бывший. создание критериев/запросов на сервисном уровне в случае MongoDB.
  • Разместите кэширование для необходимых методов обслуживания.

5. Репозиторий/Дао: этот уровень взаимодействует с БД в вашем приложении. База данных сканирует каждую запись, чтобы получить требуемый результат, если мы не разрабатываем индекс вокруг сущности/документа, что крайне неэффективно. Индексы помогают сократить пространство поиска. Прочтите это, чтобы узнать больше о работе с индексами.

  • Мы должны сначала попытаться понять методы поиска, а затем придумать правильную индексацию.
  • Создавайте индекс только тогда, когда это необходимо, так как это может сделать операции записи и удаления дорогостоящими. И ему нужно будет обновить как таблицу/документ, так и проиндексированные данные.
  • Если find необходимо получить данные на основе нескольких полей, избегайте написания нескольких методов, вместо этого попробуйте создать динамический запрос на основе заданных полей с помощью одного метода репозитория.

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

API — это интерфейс, который позволяет многим разработчикам взаимодействовать с данными. Мы всегда должны сосредоточиться на разработке отличного API, так как это очень помогает с точки зрения его использования и понимания.

Первоначально опубликовано на .