Перевод статьи подготовлен в преддверии старта курса «Scala-разработчик»  Теа, Ральф и Джесси используют tapir для описания своих конечных точек HTTP. Им нравится его удобный для программиста API, способ описания конечных точек, возможность использовать одно и то же описание для генерации сервера, клиента или документации, а также его возможности абстракции. Однако, когда дело доходит до определения серверной логики для конечных точек (то есть, что должно произойти, когда их конечные точки интерпретируются как сервер и подвергаются воздействию внешнего мира), приоритеты у них разнятся. К нашей великой удаче, все три подхода теперь покрыты tapir! Давайте рассмотрим их один за другим. 
Ральф, Джесси и Теа со своим Тапиром. София Варска Теа любит, чтобы все было просто. У нее есть один модуль, в котором определены все конечные точки ее приложения. Каждая конечная точка является специализацией baseEndpoint, которая включает в себя стандартные части: префикс пути и тип ошибки. Конечная точка содержит описание своих входов и выходов, требуются ли ей параметры запроса, заголовки, каков путь для доступа к ней и как должны выглядеть тела запросов и ответов. Также мы видим некоторые метаданные, такие как примерные значения параметров или удобочитаемые описания конечных точек. Однако определения полностью отделены от любой бизнес-логики: Только позже описания конечной точки соединяются с кодом, который должен быть запущен, когда вызывается конечная точка. Это также тот момент, когда пора переходить к определенному эффектвраперу. Теа использует Future для управления параллелизмом и объединения операций ввода-вывода, поэтому все ее методы бизнес-логики возвращают Future. Более того, поскольку ошибки, которые использует Теа, являются подклассом Exception, а методы бизнес-логики представляют ошибки как неудачные фьючерсы, она может использовать метод для объединения конечной точки с ее серверной логикой, которая восстанавливает ошибки от неудачных эффектов. Наконец, конечные точки сервера могут быть затем преобразованы, например, к akka-http Route, и представлены миру с помощью akka-http сервера. Ральфу ближе немного другой подход. Как вы могли заметить, все конечные точки нуждаются в аутентификации, и он хотел бы использовать по максимуму этот факт. В случае Ральфа аутентификация основана на токенах предъявителя, отправляемых в заголовке Authorization. Как и у Теи, у Ральфа есть один модуль, в котором определены все конечные точки. Однако, чтобы максимально упростить процесс определения новой аутентифицированной конечной точки, Ральф определил базовую конечную точку, в которую встроена логика аутентификации. Модель и серверная логика, используемые в приложении Ральфа Эта базовая конечная точка уже содержит часть бизнес-логики. Эта частичная логика использует все входные данные, определенные до сих пор (отсюда и название метода для его предоставления: serverLogicForCurrent), и выдает промежуточный результат (аутентифицированный пользователь): Как только мы предоставим частичную логику, мы получим значение типа PartialServerEndpoint. Такая конечная точка может быть дополнительно расширена путем добавления большего количества входов/выходов или предоставления большего количества логических частей (каждый раз потребляя все входы, определенные до сих пор). Однако ошибки зафиксированы! Это потому, что частичная логика, которую мы предоставили изначально, также может дать сбой — и для этого она должна вызвать либо ошибку, либо промежуточный результат. Для каждой специализации базовой конечной точки после того, как мы добавили все входы/выходы, мы можем завершить конечную точку, предоставив серверную логику, которая потребляет кортеж: промежуточные результаты (здесь: User) и остальные входные данные. Вы, вероятно, заметили, что Ральф представляет ошибки как простые case классы. Кроме того, Ральф пользуется эффектом типа данных IO для управления эффектами в своем приложении. Следовательно, его логические функции возвращают значения типа IO[Either[Error, _]]. После заполнения частичной серверной конечной точки оставшейся логикой мы получаем ServerEndpoint (так же, как и в случае с Теа). Теперь мы можем раскрыть его, используя интерпретатор, который поддерживает IO значения, такие как http4s. Джесси использует конечные точки tapir не только для предоставления сервера и создания документации по конечным точкам, но также для описания и выполнения клиентских вызовов. Вот почему ее описания конечных точек живут в совершенно отдельном модуле, который зависит только от tapir-core и tapir-json-circe. Просто нет никакого способа определить какую-либо часть бизнес-логики вместе с конечными точками. Однако ее требования ничем не отличаются от требований Ральфа. Все ее конечные точки также требуют аутентификации. Она также имеет базовую конечную точку, которая описывает как конечные точки снабжены средствами защиты (здесь, используя cookies): Однако она не может использовать тот же метод, который описан выше, чтобы определить базовую конечную точку в сочетании с логикой аутентификации. Вот почему она использует другой подход. Предоставляя серверную логику для конечных точек (которые полностью описаны в отдельном модуле), Джесси использует serverLogicPart, чтобы сначала предоставить базовые части серверной логики (логика аутентификации), а затем остальные. serverLogicPart потребляет только часть ввода, определенную на данный момент (в отличии от предыдущих, где потребляется весь определенный ввод). Однако возвращаемое значение типа ServerEndpointInParts нельзя использовать для расширения конечной точки большим количеством входов или выходов. Мы можем предоставить только больше логических частей, производящих либо ошибку, либо промежуточное значение, либо дополнить логику функцией, которая (как в случае Ральфа) принимает кортеж, содержащий частичные, промежуточные результаты и неиспользованный ввод. Таким образом, логика аутентификации по-прежнему централизована и может использоваться повторно, и ее можно легко составить с помощью функций, которые требуют для работы аутентифицированного User: Как в случаях Теи и Ральфа, окончательное значение имеет тип ServerEndpoint. Как видите, Джесси использует Future для представления сайдэффектов и серверного интерпретатора akka-http. Для предоставлении серверной логики конечной точке у нас есть три подхода: Можно сказать, что это на два способа предоставления серверной логики больше, чем нужно. Однако у библиотек есть свои законы. Это всегда вопрос предоставления пользователям гибкости там, где это действительно полезно, при одновременном ограничении других частей во избежание ненужного выбора. В данном случае хорошо иметь выбор. Варианты использования, которые мы хотели бы охватить, просто все разные, и не существует универсального решения. Будьте как Теа, Ральф или Джесси, и используйте tapir, чтобы раскрыть свои конечные точки HTTP! Узнать подробнее о курсе «Scala-разработчик» CRM/Email-маркетолог