Ques/Help/Req Как мы внедряли Design API First. Показываем на примере сервиса аутентификации

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Привет, Хабр! На связи Антон, руководитель Архитектурного комитета компании SimbirSoft. Вместе с моими коллегами в прошлой статье мы рассказали про особенности применения подхода Design API First. Сегодня покажем, как реализуется этот подход на практике на примере сервиса аутентификации пользователей.

Как мы внедряли Design API First. Показываем на примере сервиса аутентификации0


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

Алгоритм проектирования API состоит из 7 шагов:

Рисунок 1. Общий алгоритм проектирования структуры API1
Рисунок 1. Общий алгоритм проектирования структуры API

Ниже рассмотрим каждый шаг алгоритма на примере проектирования API для сервиса аутентификации.

1. Анализ бизнес-требований​


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

2. Выявление общих компонентов и объектов автоматизации​


Можно выделить следующие компоненты и процессы, которые будут использоваться в качестве объектов автоматизации:


  • учетная запись пользователя;


  • логин пользователя (+ его изменение);


  • пароль пользователя (+ его изменение);


  • email (как логин + его изменение и подтверждение);


  • телефон (как логин + его изменение и подтверждение);


  • открытая сессия (может быть связана с конкретным устройством, IP);


  • Access-токен (коротко живущий ключ для доступа к сессии);


  • Refresh-токен (одноразовый ключ для продления сессии);


  • регистрация нового пользователя в системе;


  • авторизация пользователя;


  • восстановление доступа.

3. Описание базовых сценариев​


Для описания базовых сценариев удобно использовать Sequence-диаграммы в нотации UML, хотя на данном этапе это не так принципиально, подойдет и другой удобный инструмент. В первом приближении описываем процесс в самом общем виде, для того чтобы обозначить потоки информации. На следующих итерациях осуществляется постепенная детализация. Иногда этот процесс требует возвращения к пункту 2 для уточнения.

Рисунок 2. Пример первичной диаграммы процесса аутентификации пользователя через логин и пароль2
Рисунок 2. Пример первичной диаграммы процесса аутентификации пользователя через логин и пароль

Для создания такой диаграммы использовался инструмент PlantUML.

# Аутентификация пользователя через логин и пароль @startuml !theme mars skinparam { MaxMessageSize 250 } skinparam sequence { ParticipantPadding 125 MessageAlign center } participant «User» as usr order 10 participant «WebApp» as app order 20 participant «Auth» as auth order 30 title Аутентификация пользователя через логин и пароль usr -> app: Нажатие кнопки «Аутентификация» app -> app: Отображение формы аутентификации пользователя usr -> app: Заполнение полей: логин, пароль; нажатие кнопки «Войти» app -> auth: Запрос на получение доступа к аккаунту пользователя auth -> auth: Валидация данных alt #f0fff0 Валидация OK auth -> auth: Генерация access и refresh токенов app <— auth: Success app -> app: Отображение главного экрана аккаунта else #fff0f0 Валидация ERROR app <— auth: Error app -> app: Отображение сообщения об ошибке end @enduml

4. Верхнеуровневое проектирование структуры endpoints​


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

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

5. Детальная проработка endpoints​


Здесь описываются входные и выходные параметры в виде объектов OpenAPI. При этом важно именование объектов, чтобы можно было определить, для чего они предназначены и в каком действии участвуют. И поскольку наша цель создать обобщенную спецификацию, то описываем не только конкретные объекты, но и их абстракции. OpenAPI это позволяет сделать. А уже в конкретных проектах эти абстракции будут заменены на конкретные объекты и оставлены только необходимые эндпоинты. Также на этом шаге постоянно проверяется логика взаимодействия объектов. При выявлении каких-либо новых деталей, противоречий, неполноты данных возвращаемся к пункту 4.

/v1/signin: post: summary: Auth/R2. Метод получения доступа к аккаунту пользователя description: Метод предназначен для аутентификации пользователя под указанным логином/имейлом/телефоном, соответствующим аккаунту в БД operationId: authAccount tags: — Auth parameters: — $ref: «#/components/parameters/App.Request.Header.acceptLanguage» — $ref: «#/components/parameters/App.Request.Header.correlationId» — $ref: «#/components/parameters/App.Request.Header.platform» requestBody: required: true content: application/json;charset=UTF-8: schema: $ref: «#/components/schemas/Auth.Request.Model.AuthAccount» responses: «201»: # Доступ к аккаунту пользователя разрешён $ref: «#/components/responses/Auth.Response.SuccessAccessAccount» «202»: # На email/телефон было отправлено сообщение с кодом подтверждения входа в свой аккаунт $ref: «#/components/responses/Auth.Response.WaitingAccessAccount» «400»: # Логин/email/телефон должен быть указан # Логин/email/телефон некорректен или не существует # Пара логин — пароль не существует $ref: «#/components/responses/App.Response.Error400» «403»: $ref: «#/components/responses/App.Response.Error403» «500»: $ref: «#/components/responses/App.Response.Error5XX»

6. Разделение endpoints на компоненты​


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


  • Auth – основной компонент для создания новых учетных записей, входа в систему, обновления токенов, восстановления доступа.


  • Auth.Change – компонент для изменения критически важных с точки зрения безопасности полей (логин, пароль, email, телефон).


  • Auth.Operations – компонент, отвечающий за подтверждение пользователем любых важных операций различными способами (по паролю, коду подтверждения отправленного на email и по SMS), начиная от регистрации аккаунта и заканчивая операциями в бизнес-логике конкретного проекта.


  • Auth.Session – компонент для отображения и управления текущими сессиями пользователя в целях контроля его захода в систему под различными устройствами.


  • Auth.Check – вспомогательный компонент для быстрой проверки: не занят ли уже логин, указанный при регистрации, или соответствует ли пароль всем требованиям системы.

7. Детализация ограничений и описание ошибок​


На этом этапе детализируем ограничения для полей объектов (типы данных, размеры, обязательность). Описываем подробно все коды ошибок и связанные с ними сообщения, которые могут возвращать эндпоинты. Опять же возвращаемся к пункту 4, чтобы максимально детализировать сценарии с учетом последней информации. Описание кодов ошибок можно увидеть в Листинге 2, а пример описания ограничений приведен в Листинге 3:

Auth.Request.Model.CreateLogin: type: object required: — userLogin — userPassword properties: userLogin: description: Логин пользователя, к которому будет привязан созданный аккаунт type: string format: login minLength: 5 maxLength: 32 example: «user-login» userPassword: description: Пароль от аккаунта пользователя type: string format: password minLength: 8 maxLength: 32 example: «DfK0p8Kjp19SkHEd» Auth.Request.Model.AccessRecoveryByEmail: type: object required: — userEmail properties: userEmail: description: email привязаный к аккаунту пользователя type: string maxLength: 128 example: «user-email@localhost»

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

Исходя из нашего примера, получился такой набор методов:



Описание метода

Endpoint

Метод

1.​

Auth/R1. Метод создания аккаунта пользователя​

/v1/signup​

POST​

2.​

Auth/R2. Метод получения доступа к аккаунту пользователя​

/v1/signin​

POST​

3.​

Auth/R3. Метод получения информации об аккаунте​

/v1/auth​

GET​

4.​

Auth/R4. Метод генерации новых access и refresh токенов​

/v1/auth​

POST​

5.​

Auth/R5. Метод генерации access и refresh токенов по токену операции​

/v1/auth/{operationToken}​

POST​

6.​

Auth/R6. Метод восстановления доступа к аккаунту​

/v1/auth/access-recovery​

POST​

7.​

Auth/R7. Метод установки нового пароля пользователя​

/v1/auth/password-set/{operationToken}​

PUT​

8.​

Auth/CH/R1. Метод изменения логина пользователя​

/v1/auth/login​

PATCH​

9.​

Auth/CH/R2. Метод изменения пароля пользователя​

/v1/auth/password​

PATCH​

10.​

Auth/CH/R3. Метод изменения PIN-кода пользователя​

/v1/auth/pin​

PATCH​

11.​

Auth/CH/R4. Метод изменения email пользователя​

/v1/auth/email​

PATCH​

12.​

Auth/CH/R5. Метод изменения телефона пользователя​

/v1/auth/phone​

PATCH​

13.​

Auth/OP/R1. Метод получения информации об операции​

/v1/auth/operation/{operationToken}​

GET​

14.​

Auth/OP/R2. Метод подтверждения операции​

/v1/auth/operation/{operationToken}​

PUT​

15.​

Auth/OP/R3. Метод отмены операции​

/v1/auth/operation/{operationToken}​

DELETE​

16.​

Auth/SS/R1. Метод получения списка сессий пользователя​

/v1/auth/sessions​

GET​

17.​

Auth/SS/R2. Метод уничтожения открытых сессий, кроме текущей​

/v1/auth/sessions​

DELETE​

18.​

Auth/SS/R3. Метод уничтожения указанной сессий​

/v1/auth/sessions/{sessionHash}​

DELETE​

19.​

Auth/CK/R1. Метод проверяет, не занят ли уже логин​

/v1/auth/login-check​

POST​

20.​

Auth/CK/R2. Метод проверки пароля на его сложность​

/v1/auth/password-check​

POST​

21.​

Auth/CK/R3. Метод проверяет, не занят ли уже email​

/v1/auth/email-check​

POST​

22.​

Auth/CK/R4. Метод проверяет, не занят ли уже телефон​

/v1/auth/phone-check​

POST​

Заключение​


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

На основе готовой OpenAPI-спецификации можно генерировать заготовки кода сервера и клиента, оборачивая это в различные враперы или путем наследования подключать в свои проекты. Спецификации хранятся в отдельном хранилище, из которого можно быстро выяснить, как должны общаться серверы и клиенты между собой. Далее DevOps-специалисты собирают CI, при изменении спецификации перегенерируется код в соответствии с новой спецификацией. Есть возможность на этапе изменения схемы спецификации отловить несоответствия. Конечно, для этого должны быть написаны соответствующие тесты, которые бы это отслеживали. Про автоматизацию процесса тестирования на основе спецификаций мы расскажем в одной из следующих статей
🙂


1 часть: Design API First как паттерн проектирования контрактов межсервисного взаимодействия

Спасибо за внимание!

Другие полезные материалы для разработчиков и архитекторов в IT публикуем в наших соцсетях — ВК и Telegram.
 
198 114Темы
635 085Сообщения
3 618 401Пользователи
EeOneНовый пользователь
Верх